ncurses 5.9 - patch 20130816
[ncurses.git] / progs / tic.c
index 74136e8e10bdd41c010ef557b745440cc7d132d7..e1eb7e095567f624dd311b7f8be734d7d6962dfe 100644 (file)
@@ -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 <hashed_db.h>
 #include <transform.h>
 
-MODULE_ID("$Id: tic.c,v 1.169 2012/04/14 21:34:26 tom Exp $")
+MODULE_ID("$Id: tic.c,v 1.187 2013/08/17 21:15:15 tom Exp $")
 
 #define STDIN_NAME "<stdin>"
 
@@ -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 = umask(077);
        int fd = mkstemp(filename);
        if (fd >= 0)
            result = fdopen(fd, "w");
+       umask(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,6 +1244,48 @@ 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);
@@ -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
@@ -1431,6 +1506,7 @@ uses_SGR_39_49(const char *value)
 static void
 check_screen(TERMTYPE *tp)
 {
+#if NCURSES_XNAMES
     if (_nc_user_definable) {
        int have_XT = tigetflag("XT");
        int have_XM = tigetflag("XM");
@@ -1482,6 +1558,7 @@ check_screen(TERMTYPE *tp)
                _nc_warning("Expected XT to be set, given kmous");
        }
     }
+#endif
 }
 
 /*
@@ -1795,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(),
@@ -1807,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)
  */
@@ -1815,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
@@ -1823,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);