X-Git-Url: http://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=progs%2Ftic.c;h=6ee1766604343a6f7b9b5e068bcc67b0622b34f4;hp=4881d655322b7e4674111430e854a253b4ada21e;hb=ff4cca6e1dfc932e229643403cdd59a6dd4b1abb;hpb=70e1890695998ac225c5a2a3006500372e1987a1 diff --git a/progs/tic.c b/progs/tic.c index 4881d655..6ee17666 100644 --- a/progs/tic.c +++ b/progs/tic.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc. * + * Copyright (c) 1998-2012,2013 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 * @@ -46,7 +46,7 @@ #include #include -MODULE_ID("$Id: tic.c,v 1.165 2012/03/24 22:07:10 tom Exp $") +MODULE_ID("$Id: tic.c,v 1.188 2013/08/24 21:48:21 tom Exp $") #define STDIN_NAME "" @@ -57,6 +57,7 @@ static FILE *tmp_fp; static bool capdump = FALSE; /* running as infotocap? */ static bool infodump = FALSE; /* running as captoinfo? */ static bool showsummary = FALSE; +static char **namelst = 0; static const char *to_remove; static void (*save_check_termtype) (TERMTYPE *, bool); @@ -105,8 +106,10 @@ free_namelist(char **src) #endif static void -cleanup(char **namelst GCC_UNUSED) +cleanup(void) { + int rc; + #if NO_LEAKS free_namelist(namelst); #endif @@ -114,10 +117,12 @@ cleanup(char **namelst GCC_UNUSED) fclose(tmp_fp); if (to_remove != 0) { #if HAVE_REMOVE - remove(to_remove); + rc = remove(to_remove); #else - unlink(to_remove); + rc = unlink(to_remove); #endif + if (rc != 0) + perror(to_remove); } } @@ -125,7 +130,6 @@ static void failed(const char *msg) { perror(msg); - cleanup((char **) 0); ExitProgram(EXIT_FAILURE); } @@ -294,8 +298,10 @@ put_translate(int c) if (in_name) { if (used + 1 >= have) { have += 132; - namebuf = typeRealloc(char, have, namebuf); - suffix = typeRealloc(char, have, suffix); + if ((namebuf = typeRealloc(char, have, namebuf)) == 0) + failed("put_translate namebuf"); + if ((suffix = typeRealloc(char, have, suffix)) == 0) + failed("put_translate suffix"); } if (c == '\n' || c == '@') { namebuf[used++] = '\0'; @@ -374,9 +380,11 @@ open_tempfile(char *filename) _nc_STRCPY(filename, "/tmp/XXXXXX", PATH_MAX); #if HAVE_MKSTEMP { + int oldmask = (int) umask(077); int fd = mkstemp(filename); if (fd >= 0) result = fdopen(fd, "w"); + umask((mode_t) oldmask); } #else if (tmpnam(filename) != 0) @@ -388,13 +396,17 @@ open_tempfile(char *filename) static FILE * copy_input(FILE *source, const char *filename, char *alt_file) { + char my_altfile[PATH_MAX]; FILE *result = 0; - FILE *target = open_tempfile(alt_file); + FILE *target = 0; int ch; + if (alt_file == 0) + alt_file = my_altfile; + if (source == 0) { failed("copy_input (source)"); - } else if (target == 0) { + } else if ((target = open_tempfile(alt_file)) == 0) { failed("copy_input (target)"); } else { clearerr(source); @@ -420,7 +432,7 @@ copy_input(FILE *source, const char *filename, char *alt_file) */ result = fopen(alt_file, "r+"); fclose(target); - to_remove = alt_file; + to_remove = strdup(alt_file); } return result; } @@ -488,7 +500,8 @@ make_namelist(char *src) } } if (pass == 1) { - dst = typeCalloc(char *, nn + 1); + if ((dst = typeCalloc(char *, nn + 1)) == 0) + failed("make_namelist"); rewind(fp); } } @@ -510,8 +523,10 @@ make_namelist(char *src) if (mark == '\0') break; } - if (pass == 1) - dst = typeCalloc(char *, nn + 1); + if (pass == 1) { + if ((dst = typeCalloc(char *, nn + 1)) == 0) + failed("make_namelist"); + } } } if (showsummary && (dst != 0)) { @@ -541,7 +556,7 @@ matches(char **needle, const char *haystack) return (code); } -static const char * +static char * valid_db_path(const char *nominal) { struct stat sb; @@ -550,6 +565,8 @@ valid_db_path(const char *nominal) size_t need = strlen(nominal) + sizeof(suffix); char *result = malloc(need); + if (result == 0) + failed("valid_db_path"); _nc_STRCPY(result, nominal, need); if (strcmp(result + need - sizeof(suffix), suffix)) { _nc_STRCAT(result, suffix, need); @@ -610,7 +627,7 @@ static void show_databases(const char *outdir) { bool specific = (outdir != 0) || getenv("TERMINFO") != 0; - const char *result; + char *result; const char *tried = 0; if (outdir == 0) { @@ -618,6 +635,7 @@ show_databases(const char *outdir) } if ((result = valid_db_path(outdir)) != 0) { printf("%s\n", result); + free(result); } else { tried = outdir; } @@ -625,6 +643,7 @@ show_databases(const char *outdir) if ((outdir = _nc_home_terminfo())) { if ((result = valid_db_path(outdir)) != 0) { printf("%s\n", result); + free(result); } else if (!specific) { tried = outdir; } @@ -667,7 +686,6 @@ main(int argc, char *argv[]) bool limited = TRUE; char *tversion = (char *) NULL; const char *source_file = "terminfo"; - char **namelst = 0; char *outdir = (char *) NULL; bool check_only = FALSE; bool suppress_untranslatable = FALSE; @@ -675,6 +693,7 @@ main(int argc, char *argv[]) log_fp = stderr; _nc_progname = _nc_rootname(argv[0]); + atexit(cleanup); if ((infodump = same_program(_nc_progname, PROG_CAPTOINFO)) != FALSE) { outform = F_TERMINFO; @@ -764,7 +783,6 @@ main(int argc, char *argv[]) break; case 'V': puts(curses_version()); - cleanup(namelst); ExitProgram(EXIT_SUCCESS); case 'c': check_only = TRUE; @@ -836,7 +854,6 @@ main(int argc, char *argv[]) (void) fprintf(stderr, "%s: Sorry, -e can't be used without -I or -C\n", _nc_progname); - cleanup(namelst); ExitProgram(EXIT_FAILURE); } #endif /* HAVE_BIG_CORE */ @@ -879,7 +896,6 @@ main(int argc, char *argv[]) _nc_progname, _nc_progname, usage_string); - cleanup(namelst); ExitProgram(EXIT_FAILURE); } } @@ -918,7 +934,6 @@ main(int argc, char *argv[]) /* do use resolution */ if (check_only || (!infodump && !capdump) || forceresolve) { if (!_nc_resolve_uses2(TRUE, literal) && !check_only) { - cleanup(namelst); ExitProgram(EXIT_FAILURE); } } @@ -1013,7 +1028,6 @@ main(int argc, char *argv[]) else fprintf(log_fp, "No entries written\n"); } - cleanup(namelst); ExitProgram(EXIT_SUCCESS); } @@ -1210,6 +1224,19 @@ check_ansi_cursor(char *list[4]) } #define EXPECTED(name) if (!PRESENT(name)) _nc_warning("expected " #name) +#define UNEXPECTED(name) if (PRESENT(name)) _nc_warning("unexpected " #name ", for %s", why) + +static void +check_noaddress(TERMTYPE *tp, const char *why) +{ + UNEXPECTED(column_address); + UNEXPECTED(cursor_address); + UNEXPECTED(cursor_home); + UNEXPECTED(cursor_mem_address); + UNEXPECTED(cursor_to_ll); + UNEXPECTED(row_address); + UNEXPECTED(row_address); +} static void check_cursor(TERMTYPE *tp) @@ -1217,13 +1244,55 @@ check_cursor(TERMTYPE *tp) int count; char *list[4]; + if (hard_copy) { + check_noaddress(tp, "hard_copy"); + } else if (generic_type) { + check_noaddress(tp, "generic_type"); + } else if (strchr(tp->term_names, '+') == 0) { + int y = 0; + int x = 0; + if (PRESENT(column_address)) + ++y; + if (PRESENT(cursor_address)) + y = x = 10; + if (PRESENT(cursor_home)) + ++y, ++x; + if (PRESENT(cursor_mem_address)) + y = x = 10; + if (PRESENT(cursor_to_ll)) + ++y, ++x; + if (PRESENT(row_address)) + ++x; + if (PRESENT(cursor_down)) + ++y; + if (PRESENT(cursor_up)) + ++y; + if (PRESENT(cursor_left)) + ++x; + if (PRESENT(cursor_right)) + ++x; + if (x < 2 && y < 2) { + _nc_warning("terminal lacks cursor addressing"); + } else { + if (x < 2) + _nc_warning("terminal lacks cursor column-addressing"); + if (y < 2) + _nc_warning("terminal lacks cursor row-addressing"); + } + } + + /* it is rare to have an insert-line feature without a matching delete */ + ANDMISSING(parm_insert_line, insert_line); + ANDMISSING(parm_delete_line, delete_line); + ANDMISSING(parm_insert_line, parm_delete_line); + /* if we have a parameterized form, then the non-parameterized is easy */ ANDMISSING(parm_down_cursor, cursor_down); ANDMISSING(parm_up_cursor, cursor_up); ANDMISSING(parm_left_cursor, cursor_left); ANDMISSING(parm_right_cursor, cursor_right); - /* Given any of a set of cursor movement, the whole set should be present. + /* Given any of a set of cursor movement, the whole set should be present. * Technically this is not true (we could use cursor_address to fill in * unsupported controls), but it is likely. */ @@ -1390,6 +1459,12 @@ check_keypad(TERMTYPE *tp) if (*show != '\0') _nc_warning("vt100 keypad map incomplete:%s", show); } + + /* + * These warnings are useful for consistency checks - it is possible that + * there are real terminals with mismatches in these + */ + ANDMISSING(key_ic, key_dc); } static void @@ -1418,6 +1493,74 @@ check_printer(TERMTYPE *tp) ANDMISSING(parm_up_micro, micro_up); } +static bool +uses_SGR_39_49(const char *value) +{ + return (strstr(value, "39;49") != 0 + || strstr(value, "49;39") != 0); +} + +/* + * Check consistency of termcap extensions related to "screen". + */ +static void +check_screen(TERMTYPE *tp) +{ +#if NCURSES_XNAMES + if (_nc_user_definable) { + int have_XT = tigetflag("XT"); + int have_XM = tigetflag("XM"); + int have_bce = back_color_erase; + bool have_kmouse = FALSE; + bool use_sgr_39_49 = FALSE; + char *name = _nc_first_name(tp->term_names); + + if (!VALID_BOOLEAN(have_bce)) { + have_bce = FALSE; + } + if (!VALID_BOOLEAN(have_XM)) { + have_XM = FALSE; + } + if (!VALID_BOOLEAN(have_XT)) { + have_XT = FALSE; + } + if (VALID_STRING(key_mouse)) { + have_kmouse = !strcmp("\033[M", key_mouse); + } + if (VALID_STRING(orig_colors)) { + use_sgr_39_49 = uses_SGR_39_49(orig_colors); + } else if (VALID_STRING(orig_pair)) { + use_sgr_39_49 = uses_SGR_39_49(orig_pair); + } + + 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"); + } else if (have_XT) { + if (!have_kmouse && have_bce) { + if (VALID_STRING(key_mouse)) { + _nc_warning("Value of kmous inconsistent with screen's usage"); + } else { + _nc_warning("Expected kmous capability with XT"); + } + } + if (!have_bce && max_colors > 0) + _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"); + 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"); + } + } +#endif +} + /* * Returns the expected number of parameters for the given capability. */ @@ -1729,7 +1872,7 @@ static void show_where(unsigned level) { if (_nc_tracing >= DEBUG_LEVEL(level)) { - char my_name[256]; + char my_name[MAX_NAME_SIZE]; _nc_get_type(my_name); _tracef("\"%s\", line %d, '%s'", _nc_get_source(), @@ -1741,6 +1884,58 @@ show_where(unsigned level) #define show_where(level) /* nothing */ #endif +typedef struct { + int keycode; + const char *name; + const char *value; +} NAME_VALUE; + +static NAME_VALUE * +get_fkey_list(TERMTYPE *tp) +{ + NAME_VALUE *result = typeMalloc(NAME_VALUE, NUM_STRINGS(tp) + 1); + const struct tinfo_fkeys *all_fkeys = _nc_tinfo_fkeys; + int used = 0; + int j; + + if (result == 0) + failed("get_fkey_list"); + + for (j = 0; all_fkeys[j].code; j++) { + char *a = tp->Strings[all_fkeys[j].offset]; + if (VALID_STRING(a)) { + result[used].keycode = (int) all_fkeys[j].code; + result[used].name = strnames[all_fkeys[j].offset]; + result[used].value = a; + ++used; + } + } +#if NCURSES_XNAMES + for (j = STRCOUNT; j < NUM_STRINGS(tp); ++j) { + const char *name = ExtStrname(tp, j, strnames); + if (*name == 'k') { + result[used].keycode = -1; + result[used].name = name; + result[used].value = tp->Strings[j]; + ++used; + } + } +#endif + result[used].keycode = 0; + return result; +} + +static void +show_fkey_name(NAME_VALUE * data) +{ + if (data->keycode > 0) { + fprintf(stderr, " %s", keyname(data->keycode)); + fprintf(stderr, " (capability \"%s\")", data->name); + } else { + fprintf(stderr, " capability \"%s\"", data->name); + } +} + /* other sanity-checks (things that we don't want in the normal * logic that reads a terminfo entry) */ @@ -1749,7 +1944,6 @@ check_termtype(TERMTYPE *tp, bool literal) { bool conflict = FALSE; unsigned j, k; - char fkeys[STRCOUNT]; /* * A terminal entry may contain more than one keycode assigned to @@ -1757,41 +1951,47 @@ check_termtype(TERMTYPE *tp, bool literal) * return one (the last one assigned). */ if (!(_nc_syntax == SYN_TERMCAP && capdump)) { - memset(fkeys, 0, sizeof(fkeys)); - for (j = 0; _nc_tinfo_fkeys[j].code; j++) { - char *a = tp->Strings[_nc_tinfo_fkeys[j].offset]; + char *check = calloc((size_t) (NUM_STRINGS(tp) + 1), sizeof(char)); + NAME_VALUE *given = get_fkey_list(tp); + + if (check == 0) + failed("check_termtype"); + + for (j = 0; given[j].keycode; ++j) { + const char *a = given[j].value; bool first = TRUE; - if (!VALID_STRING(a)) - continue; - for (k = j + 1; _nc_tinfo_fkeys[k].code; k++) { - char *b = tp->Strings[_nc_tinfo_fkeys[k].offset]; - if (!VALID_STRING(b) - || fkeys[k]) + + for (k = j + 1; given[k].keycode; k++) { + const char *b = given[k].value; + if (check[k]) continue; if (!_nc_capcmp(a, b)) { - fkeys[j] = 1; - fkeys[k] = 1; + check[j] = 1; + check[k] = 1; if (first) { if (!conflict) { _nc_warning("Conflicting key definitions (using the last)"); conflict = TRUE; } - fprintf(stderr, "... %s is the same as %s", - keyname((int) _nc_tinfo_fkeys[j].code), - keyname((int) _nc_tinfo_fkeys[k].code)); + fprintf(stderr, "..."); + show_fkey_name(given + j); + fprintf(stderr, " is the same as"); + show_fkey_name(given + k); first = FALSE; } else { - fprintf(stderr, ", %s", - keyname((int) _nc_tinfo_fkeys[k].code)); + fprintf(stderr, ", "); + show_fkey_name(given + k); } } } if (!first) fprintf(stderr, "\n"); } + free(given); + free(check); } - for (j = 0; j < NUM_STRINGS(tp); j++) { + for_each_string(j, tp) { char *a = tp->Strings[j]; if (VALID_STRING(a)) check_params(tp, ExtStrname(tp, (int) j, strnames), a); @@ -1802,6 +2002,7 @@ check_termtype(TERMTYPE *tp, bool literal) check_cursor(tp); check_keypad(tp); check_printer(tp); + check_screen(tp); /* * These may be mismatched because the terminal description relies on