]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - progs/toe.c
ncurses 6.2 - patch 20211009
[ncurses.git] / progs / toe.c
index f1b836fe277123bc31895a57e03d7a766bcbfdd7..92819c195d1f3a4dc2b14dac5a486e5415b8fac0 100644 (file)
@@ -1,5 +1,6 @@
 /****************************************************************************
- * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc.              *
+ * Copyright 2018-2020,2021 Thomas E. Dickey                                *
+ * Copyright 1998-2013,2017 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            *
@@ -44,7 +45,7 @@
 #include <hashed_db.h>
 #endif
 
-MODULE_ID("$Id: toe.c,v 1.67 2012/03/10 23:22:21 tom Exp $")
+MODULE_ID("$Id: toe.c,v 1.86 2021/10/10 00:55:32 tom Exp $")
 
 #define isDotname(name) (!strcmp(name, ".") || !strcmp(name, ".."))
 
@@ -63,7 +64,7 @@ static size_t len_termdata;   /* allocated size of ptr_termdata[] */
 
 #if NO_LEAKS
 #undef ExitProgram
-static void ExitProgram(int code) GCC_NORETURN;
+static GCC_NORETURN void ExitProgram(int code);
 static void
 ExitProgram(int code)
 {
@@ -72,7 +73,7 @@ ExitProgram(int code)
 }
 #endif
 
-static void failed(const char *) GCC_NORETURN;
+static GCC_NORETURN void failed(const char *);
 
 static void
 failed(const char *msg)
@@ -99,6 +100,8 @@ new_termdata(void)
     if (want >= len_termdata) {
        len_termdata = (2 * want) + 10;
        ptr_termdata = typeRealloc(TERMDATA, len_termdata, ptr_termdata);
+       if (ptr_termdata == 0)
+           failed("ptr_termdata");
     }
 
     return ptr_termdata + use_termdata++;
@@ -124,12 +127,15 @@ compare_termdata(const void *a, const void *b)
 static void
 show_termdata(int eargc, char **eargv)
 {
-    int j, k;
-    size_t n;
-
     if (use_termdata) {
+       size_t n;
+
        if (eargc > 1) {
+           int j;
+
            for (j = 0; j < eargc; ++j) {
+               int k;
+
                for (k = 0; k <= j; ++k) {
                    printf("--");
                }
@@ -140,14 +146,20 @@ show_termdata(int eargc, char **eargv)
        if (use_termdata > 1)
            qsort(ptr_termdata, use_termdata, sizeof(TERMDATA), compare_termdata);
        for (n = 0; n < use_termdata; ++n) {
+           int nk = -1;
 
            /*
             * If there is more than one database, show how they differ.
             */
            if (eargc > 1) {
                unsigned long check = 0;
-               k = 0;
+               int k = 0;
                for (;;) {
+                   char mark = ((check == 0
+                                 || (check != ptr_termdata[n].checksum))
+                                ? '*'
+                                : '+');
+
                    for (; k < ptr_termdata[n].db_index; ++k) {
                        printf("--");
                    }
@@ -157,11 +169,10 @@ show_termdata(int eargc, char **eargv)
                     * from the first entry's checksum, print "*". Otherwise
                     * it looks enough like a duplicate to print "+".
                     */
-                   printf("%c-", ((check == 0
-                                   || (check != ptr_termdata[n].checksum))
-                                  ? '*'
-                                  : '+'));
+                   printf("%c-", mark);
                    check = ptr_termdata[n].checksum;
+                   if (mark == '*' && nk < 0)
+                       nk = (int) n;
 
                    ++k;
                    if ((n + 1) >= use_termdata
@@ -176,10 +187,12 @@ show_termdata(int eargc, char **eargv)
                }
                printf(":\t");
            }
+           if (nk < 0)
+               nk = (int) n;
 
            (void) printf("%-10s\t%s\n",
                          ptr_termdata[n].term_name,
-                         ptr_termdata[n].description);
+                         ptr_termdata[nk].description);
        }
     }
 }
@@ -230,16 +243,18 @@ make_db_name(char *dst, const char *src, unsigned limit)
     static const char suffix[] = DBM_SUFFIX;
 
     bool result = FALSE;
-    unsigned lens = sizeof(suffix) - 1;
-    unsigned size = strlen(src);
-    unsigned need = lens + size;
+    size_t lens = sizeof(suffix) - 1;
+    size_t size = strlen(src);
+    size_t need = lens + size;
 
     if (need <= limit) {
        if (size >= lens
            && !strcmp(src + size - lens, suffix)) {
            _nc_STRCPY(dst, src, PATH_MAX);
        } else {
-           _nc_SPRINTF(dst, _nc_SLIMIT(PATH_MAX) "%s%s", src, suffix);
+           _nc_SPRINTF(dst, _nc_SLIMIT(PATH_MAX) "%.*s%s",
+                       (int) (PATH_MAX - sizeof(suffix)),
+                       src, suffix);
        }
        result = TRUE;
     }
@@ -250,22 +265,25 @@ make_db_name(char *dst, const char *src, unsigned limit)
 typedef void (DescHook) (int /* db_index */ ,
                         int /* db_limit */ ,
                         const char * /* term_name */ ,
-                        TERMTYPE * /* term */ );
+                        TERMTYPE2 * /* term */ );
 
 static const char *
-term_description(TERMTYPE *tp)
+term_description(TERMTYPE2 *tp)
 {
     const char *desc;
 
-    if ((desc = strrchr(tp->term_names, '|')) == 0 || *++desc == '\0')
+    if (tp->term_names == 0
+       || (desc = strrchr(tp->term_names, '|')) == 0
+       || (*++desc == '\0')) {
        desc = "(No description)";
+    }
 
     return desc;
 }
 
 /* display a description for the type */
 static void
-deschook(int db_index, int db_limit, const char *term_name, TERMTYPE *tp)
+deschook(int db_index, int db_limit, const char *term_name, TERMTYPE2 *tp)
 {
     (void) db_index;
     (void) db_limit;
@@ -289,7 +307,7 @@ string_sum(const char *value)
 }
 
 static unsigned long
-checksum_of(TERMTYPE *tp)
+checksum_of(TERMTYPE2 *tp)
 {
     unsigned long result = string_sum(tp->term_names);
     unsigned i;
@@ -308,7 +326,7 @@ checksum_of(TERMTYPE *tp)
 
 /* collect data, to sort before display */
 static void
-sorthook(int db_index, int db_limit, const char *term_name, TERMTYPE *tp)
+sorthook(int db_index, int db_limit, const char *term_name, TERMTYPE2 *tp)
 {
     TERMDATA *data = new_termdata();
 
@@ -318,11 +336,31 @@ sorthook(int db_index, int db_limit, const char *term_name, TERMTYPE *tp)
     data->description = strmalloc(term_description(tp));
 }
 
-#if USE_TERMCAP
+#if NCURSES_USE_TERMCAP
+/*
+ * Check if the buffer contents are printable ASCII, ensuring that we do not
+ * accidentally pick up incompatible binary content from a hashed database.
+ */
+static bool
+is_termcap(char *buffer)
+{
+    bool result = TRUE;
+    while (*buffer != '\0') {
+       int ch = UChar(*buffer++);
+       if (ch == '\t')
+           continue;
+       if (ch < ' ' || ch > '~') {
+           result = FALSE;
+           break;
+       }
+    }
+    return result;
+}
+
 static void
 show_termcap(int db_index, int db_limit, char *buffer, DescHook hook)
 {
-    TERMTYPE data;
+    TERMTYPE2 data;
     char *next = strchr(buffer, ':');
     char *last;
     char *list = buffer;
@@ -345,16 +383,31 @@ show_termcap(int db_index, int db_limit, char *buffer, DescHook hook)
 }
 #endif
 
+#if NCURSES_USE_DATABASE
+static char *
+copy_entryname(DIRENT * src)
+{
+    size_t len = NAMLEN(src);
+    char *result = malloc(len + 1);
+    if (result == 0)
+       failed("copy entryname");
+    memcpy(result, src->d_name, len);
+    result[len] = '\0';
+
+    return result;
+}
+#endif
+
 static int
 typelist(int eargc, char *eargv[],
-        bool verbosity,
+        int verbosity,
         DescHook hook)
 /* apply a function to each entry in given terminfo directories */
 {
     int i;
 
     for (i = 0; i < eargc; i++) {
-#if USE_DATABASE
+#if NCURSES_USE_DATABASE
        if (_nc_is_dir_path(eargv[i])) {
            char *cwd_buf = 0;
            DIR *termdir;
@@ -372,24 +425,28 @@ typelist(int eargc, char *eargv[],
                (void) printf("#\n#%s:\n#\n", eargv[i]);
 
            while ((subdir = readdir(termdir)) != 0) {
-               size_t len = NAMLEN(subdir);
-               size_t cwd_len = len + strlen(eargv[i]) + 3;
-               char name_1[PATH_MAX];
+               size_t cwd_len;
+               char *name_1;
                DIR *entrydir;
                DIRENT *entry;
 
+               name_1 = copy_entryname(subdir);
+               if (isDotname(name_1)) {
+                   free(name_1);
+                   continue;
+               }
+
+               cwd_len = NAMLEN(subdir) + strlen(eargv[i]) + 3;
                cwd_buf = typeRealloc(char, cwd_len, cwd_buf);
                if (cwd_buf == 0)
                    failed("realloc cwd_buf");
 
                assert(cwd_buf != 0);
 
-               strncpy(name_1, subdir->d_name, len)[len] = '\0';
-               if (isDotname(name_1))
-                   continue;
-
                _nc_SPRINTF(cwd_buf, _nc_SLIMIT(cwd_len)
-                           "%s/%.*s/", eargv[i], (int) len, name_1);
+                           "%s/%s/", eargv[i], name_1);
+               free(name_1);
+
                if (chdir(cwd_buf) != 0)
                    continue;
 
@@ -399,15 +456,16 @@ typelist(int eargc, char *eargv[],
                    continue;
                }
                while ((entry = readdir(entrydir)) != 0) {
-                   char name_2[PATH_MAX];
-                   TERMTYPE lterm;
+                   char *name_2;
+                   TERMTYPE2 lterm;
                    char *cn;
                    int status;
 
-                   len = NAMLEN(entry);
-                   strncpy(name_2, entry->d_name, len)[len] = '\0';
-                   if (isDotname(name_2) || !_nc_is_file_path(name_2))
+                   name_2 = copy_entryname(entry);
+                   if (isDotname(name_2) || !_nc_is_file_path(name_2)) {
+                       free(name_2);
                        continue;
+                   }
 
                    status = _nc_read_file_entry(name_2, &lterm);
                    if (status <= 0) {
@@ -415,7 +473,8 @@ typelist(int eargc, char *eargv[],
                        (void) fprintf(stderr,
                                       "%s: couldn't open terminfo file %s.\n",
                                       _nc_progname, name_2);
-                       return (EXIT_FAILURE);
+                       free(name_2);
+                       continue;
                    }
 
                    /* only visit things once, by primary name */
@@ -424,7 +483,8 @@ typelist(int eargc, char *eargv[],
                        /* apply the selected hook function */
                        hook(i, eargc, cn, &lterm);
                    }
-                   _nc_free_termtype(&lterm);
+                   _nc_free_termtype2(&lterm);
+                   free(name_2);
                }
                closedir(entrydir);
            }
@@ -448,7 +508,7 @@ typelist(int eargc, char *eargv[],
 
                    code = _nc_db_first(capdbp, &key, &data);
                    while (code == 0) {
-                       TERMTYPE lterm;
+                       TERMTYPE2 lterm;
                        int used;
                        char *have;
                        char *cn;
@@ -459,7 +519,7 @@ typelist(int eargc, char *eargv[],
                                cn = _nc_first_name(lterm.term_names);
                                /* apply the selected hook function */
                                hook(i, eargc, cn, &lterm);
-                               _nc_free_termtype(&lterm);
+                               _nc_free_termtype2(&lterm);
                            }
                        }
                        code = _nc_db_next(capdbp, &key, &data);
@@ -470,9 +530,9 @@ typelist(int eargc, char *eargv[],
                }
            }
        }
-#endif
-#endif
-#if USE_TERMCAP
+#endif /* USE_HASHED_DB */
+#endif /* NCURSES_USE_DATABASE */
+#if NCURSES_USE_TERMCAP
 #if HAVE_BSD_CGETENT
        {
            CGETENT_CONST char *db_array[2];
@@ -485,11 +545,13 @@ typelist(int eargc, char *eargv[],
            db_array[1] = 0;
 
            if (cgetfirst(&buffer, db_array) > 0) {
-               show_termcap(i, eargc, buffer, hook);
-               free(buffer);
-               while (cgetnext(&buffer, db_array) > 0) {
+               if (is_termcap(buffer)) {
                    show_termcap(i, eargc, buffer, hook);
                    free(buffer);
+                   while (cgetnext(&buffer, db_array) > 0) {
+                       show_termcap(i, eargc, buffer, hook);
+                       free(buffer);
+                   }
                }
                cgetclose();
                continue;
@@ -504,8 +566,10 @@ typelist(int eargc, char *eargv[],
            if (verbosity)
                (void) printf("#\n#%s:\n#\n", eargv[i]);
 
-           if ((fp = fopen(eargv[i], "r")) != 0) {
+           if ((fp = safe_fopen(eargv[i], "r")) != 0) {
                while (fgets(buffer, sizeof(buffer), fp) != 0) {
+                   if (!is_termcap(buffer))
+                       break;
                    if (*buffer == '#')
                        continue;
                    if (isspace(*buffer))
@@ -542,7 +606,6 @@ main(int argc, char *argv[])
     bool invert_dependencies = FALSE;
     bool header = FALSE;
     char *report_file = 0;
-    unsigned i;
     int code;
     int this_opt, last_opt = '?';
     unsigned v_opt = 0;
@@ -630,11 +693,13 @@ main(int argc, char *argv[])
     /* maybe we want a reverse-dependency listing? */
     if (invert_dependencies) {
        ENTRY *qp, *rp;
-       int matchcount;
 
        for_entry_list(qp) {
-           matchcount = 0;
+           int matchcount = 0;
+
            for_entry_list(rp) {
+               unsigned i;
+
                if (rp->nuses == 0)
                    continue;
 
@@ -664,15 +729,17 @@ main(int argc, char *argv[])
        DBDIRS state;
        int offset;
        int pass;
-       const char *path;
        char **eargv = 0;
 
        code = EXIT_FAILURE;
        for (pass = 0; pass < 2; ++pass) {
            size_t count = 0;
+           const char *path;
 
            _nc_first_db(&state, &offset);
            while ((path = _nc_next_db(&state, &offset)) != 0) {
+               if (quick_prefix(path))
+                   continue;
                if (pass) {
                    eargv[count] = strmalloc(path);
                }
@@ -680,6 +747,8 @@ main(int argc, char *argv[])
            }
            if (!pass) {
                eargv = allocArgv(count);
+               if (eargv == 0)
+                   failed("eargv");
            } else {
                code = typelist((int) count, eargv, header, hook);
                freeArgv(eargv);
@@ -689,12 +758,15 @@ main(int argc, char *argv[])
        DBDIRS state;
        int offset;
        const char *path;
-       char **eargv = allocArgv(2);
+       char **eargv = allocArgv((size_t) 2);
        size_t count = 0;
 
+       if (eargv == 0)
+           failed("eargv");
        _nc_first_db(&state, &offset);
        if ((path = _nc_next_db(&state, &offset)) != 0) {
-           eargv[count++] = strmalloc(path);
+           if (!quick_prefix(path))
+               eargv[count++] = strmalloc(path);
        }
 
        code = typelist((int) count, eargv, header, hook);