libncurses: Import https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.5.tar.gz changes

Change-Id: I3433d30ca01359fd2e3623ede96b531f0b39cbfa
Signed-off-by: micky387 <mickaelsaibi@free.fr>
diff --git a/progs/dump_entry.c b/progs/dump_entry.c
index d59a925..be332d2 100644
--- a/progs/dump_entry.c
+++ b/progs/dump_entry.c
@@ -1,5 +1,6 @@
 /****************************************************************************
- * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc.              *
+ * Copyright 2018-2022,2023 Thomas E. Dickey                                *
+ * Copyright 1998-2016,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            *
@@ -35,17 +36,18 @@
 #define __INTERNAL_CAPS_VISIBLE
 #include <progs.priv.h>
 
-#include "dump_entry.h"
-#include "termsort.c"		/* this C file is generated */
+#include <dump_entry.h>
+#include <termsort.h>		/* this C file is generated */
 #include <parametrized.h>	/* so is this */
 
-MODULE_ID("$Id: dump_entry.c,v 1.118 2015/07/07 08:06:39 Werner.Fink Exp $")
+MODULE_ID("$Id: dump_entry.c,v 1.196 2023/05/27 20:13:10 tom Exp $")
 
-#define INDENT			8
 #define DISCARD(string) string = ABSENT_STRING
 #define PRINTF (void) printf
+#define WRAPPED 32
 
 #define OkIndex(index,array) ((int)(index) >= 0 && (int)(index) < (int) SIZEOF(array))
+#define TcOutput() (outform == F_TERMCAP || outform == F_TCONVERR)
 
 typedef struct {
     char *text;
@@ -61,7 +63,10 @@
 static int column;		/* current column, limited by 'width' */
 static int oldcol;		/* last value of column before wrap */
 static bool pretty;		/* true if we format if-then-else strings */
+static bool wrapped;		/* true if we wrap too-long strings */
+static bool did_wrap;		/* true if last wrap_concat did wrapping */
 static bool checking;		/* true if we are checking for tic */
+static int quickdump;		/* true if we are dumping compiled data */
 
 static char *save_sgr;
 
@@ -75,11 +80,12 @@
 static NCURSES_CONST char *const *str_names;
 
 static const char *separator = "", *trailer = "";
+static int indent = 8;
 
 /* cover various ports and variants of terminfo */
 #define V_ALLCAPS	0	/* all capabilities (SVr4, XSI, ncurses) */
 #define V_SVR1		1	/* SVR1, Ultrix */
-#define V_HPUX		2	/* HP/UX */
+#define V_HPUX		2	/* HP-UX */
 #define V_AIX		3	/* AIX */
 #define V_BSD		4	/* BSD */
 
@@ -89,7 +95,7 @@
 #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
 #endif
 
-#define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && OBSOLETE(n))
+#define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && (sortmode != S_VARIABLE) && OBSOLETE(n))
 
 #if NCURSES_XNAMES
 #define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
@@ -101,9 +107,7 @@
 #define StrIndirect(j)  ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
 #endif
 
-static void failed(const char *) GCC_NORETURN;
-
-static void
+static GCC_NORETURN void
 failed(const char *s)
 {
     perror(s);
@@ -120,7 +124,7 @@
 	if (dst->text == 0)
 	    failed("strncpy_DYN");
     }
-    (void) strncpy(dst->text + dst->used, src, need);
+    _nc_STRNCPY(dst->text + dst->used, src, need + 1);
     dst->used += need;
     dst->text[dst->used] = 0;
 }
@@ -189,17 +193,23 @@
 dump_init(const char *version,
 	  int mode,
 	  int sort,
+	  bool wrap_strings,
 	  int twidth,
 	  int theight,
 	  unsigned traceval,
 	  bool formatted,
-	  bool check)
+	  bool check,
+	  int quick)
 /* set up for entry display */
 {
     width = twidth;
     height = theight;
     pretty = formatted;
+    wrapped = wrap_strings;
     checking = check;
+    quickdump = (quick & 3);
+
+    did_wrap = (width <= 0);
 
     /* versions */
     if (version == 0)
@@ -244,6 +254,7 @@
 	trailer = "\\\n\t:";
 	break;
     }
+    indent = 8;
 
     /* implement sort modes */
     switch (sortmode = sort) {
@@ -287,7 +298,7 @@
 		       _nc_progname, width, tversion, outform);
 }
 
-static TERMTYPE *cur_type;
+static TERMTYPE2 *cur_type;
 
 static int
 dump_predicate(PredType type, PredIdx idx)
@@ -310,7 +321,7 @@
     return (FALSE);		/* pacify compiler */
 }
 
-static void set_obsolete_termcaps(TERMTYPE *tp);
+static void set_obsolete_termcaps(TERMTYPE2 *tp);
 
 /* is this the index of a function key string? */
 #define FNKEY(i) \
@@ -413,22 +424,257 @@
     oldcol = column;
     trim_trailing();
     strcpy_DYN(&outbuf, trailer);
-    column = INDENT;
+    column = indent;
+}
+
+static int
+op_length(const char *src, int offset)
+{
+    int result = 0;
+
+    if (offset > 0 && src[offset - 1] == '\\') {
+	result = 0;
+    } else {
+	int ch;
+
+	result++;		/* for '%' mark */
+	ch = src[offset + result];
+	if (TcOutput()) {
+	    if (ch == '>') {
+		result += 3;
+	    } else if (ch == '+') {
+		result += 2;
+	    } else {
+		result++;
+	    }
+	} else if (ch == '\'') {
+	    result += 3;
+	} else if (ch == L_CURL[0]) {
+	    int n = result;
+	    while ((ch = src[offset + n]) != '\0') {
+		if (ch == R_CURL[0]) {
+		    result = ++n;
+		    break;
+		}
+		n++;
+	    }
+	} else if (strchr("pPg", ch) != 0) {
+	    result += 2;
+	} else {
+	    result++;		/* ordinary operator */
+	}
+    }
+    return result;
+}
+
+/*
+ * When wrapping too-long strings, avoid splitting a backslash sequence, or
+ * a terminfo '%' operator.  That will leave things a little ragged, but avoids
+ * a stray backslash at the end of the line, as well as making the result a
+ * little more readable.
+ */
+static int
+find_split(const char *src, int step, int size)
+{
+    int result = size;
+
+    if (size > 0) {
+	/* check if that would split a backslash-sequence */
+	int mark = size;
+	int n;
+
+	for (n = size - 1; n > 0; --n) {
+	    int ch = UChar(src[step + n]);
+	    if (ch == '\\') {
+		if (n > 0 && src[step + n - 1] == ch)
+		    --n;
+		mark = n;
+		break;
+	    } else if (!isalnum(ch)) {
+		break;
+	    }
+	}
+	if (mark < size) {
+	    result = mark;
+	} else {
+	    /* check if that would split a backslash-sequence */
+	    for (n = size - 1; n > 0; --n) {
+		int ch = UChar(src[step + n]);
+		if (ch == '%') {
+		    int need = op_length(src, step + n);
+		    if ((n + need) > size) {
+			mark = n;
+		    }
+		    break;
+		}
+	    }
+	    if (mark < size) {
+		result = mark;
+	    }
+	}
+    }
+    return result;
+}
+
+/*
+ * If we are going to wrap lines, we cannot leave literal spaces because that
+ * would be ambiguous if we split on that space.
+ */
+static char *
+fill_spaces(const char *src)
+{
+    const char *fill = "\\s";
+    size_t need = strlen(src);
+    size_t size = strlen(fill);
+    char *result = 0;
+    int pass;
+    size_t s, d;
+    for (pass = 0; pass < 2; ++pass) {
+	for (s = d = 0; src[s] != '\0'; ++s) {
+	    if (src[s] == ' ') {
+		if (pass) {
+		    _nc_STRCPY(&result[d], fill, need + 1 - d);
+		    d += size;
+		} else {
+		    need += size;
+		}
+	    } else {
+		if (pass) {
+		    result[d++] = src[s];
+		} else {
+		    ++d;
+		}
+	    }
+	}
+	if (pass) {
+	    result[d] = '\0';
+	} else {
+	    result = calloc(need + 1, sizeof(char));
+	    if (result == 0)
+		failed("fill_spaces");
+	}
+    }
+    return result;
+}
+
+typedef enum {
+    wOFF = 0
+    ,w1ST = 1
+    ,w2ND = 2
+    ,wEND = 4
+    ,wERR = 8
+} WRAPMODE;
+
+#define wrap_1ST(mode) ((mode)&w1ST)
+#define wrap_END(mode) ((mode)&wEND)
+#define wrap_ERR(mode) ((mode)&wERR)
+
+static void
+wrap_concat(const char *src, int need, unsigned mode)
+{
+    int gaps = (int) strlen(separator);
+    int want = gaps + need;
+
+    did_wrap = (width <= 0);
+    if (wrap_1ST(mode)
+	&& column > indent
+	&& column + want > width) {
+	force_wrap();
+    }
+    if ((wrap_END(mode) && !wrap_ERR(mode)) &&
+	wrapped &&
+	(width >= 0) &&
+	(column + want) > width) {
+	int step = 0;
+	int used = width > WRAPPED ? width : WRAPPED;
+	int base = 0;
+	char *p, align[9];
+	const char *my_t = trailer;
+	char *fill = fill_spaces(src);
+	int last = (int) strlen(fill);
+
+	need = last;
+
+	if (TcOutput())
+	    trailer = "\\\n\t ";
+
+	if (!TcOutput() && (p = strchr(fill, '=')) != 0) {
+	    base = (int) (p + 1 - fill);
+	    if (base > 8)
+		base = 8;
+	    _nc_SPRINTF(align, _nc_SLIMIT(align) "%*s", base, " ");
+	} else if (column > 8) {
+	    base = column - 8;
+	    if (base > 8)
+		base = 8;
+	    _nc_SPRINTF(align, _nc_SLIMIT(align) "%*s", base, " ");
+	} else {
+	    align[base] = '\0';
+	}
+	/* "pretty" overrides wrapping if it already split the line */
+	if (!pretty || strchr(fill, '\n') == 0) {
+	    int tag = 0;
+
+	    if (TcOutput() && outbuf.used && !wrap_1ST(mode)) {
+		tag = 3;
+	    }
+
+	    while ((column + (need + gaps)) > used) {
+		int size = used - tag;
+		if (step) {
+		    strcpy_DYN(&outbuf, align);
+		    size -= base;
+		}
+		if (size > (last - step)) {
+		    size = (last - step);
+		}
+		size = find_split(fill, step, size);
+		strncpy_DYN(&outbuf, fill + step, (size_t) size);
+		step += size;
+		need -= size;
+		if (need > 0) {
+		    force_wrap();
+		    did_wrap = TRUE;
+		    tag = 0;
+		}
+	    }
+	}
+	if (need > 0) {
+	    if (step)
+		strcpy_DYN(&outbuf, align);
+	    strcpy_DYN(&outbuf, fill + step);
+	}
+	if (wrap_END(mode))
+	    strcpy_DYN(&outbuf, separator);
+	trailer = my_t;
+	force_wrap();
+
+	free(fill);
+    } else {
+	strcpy_DYN(&outbuf, src);
+	if (wrap_END(mode))
+	    strcpy_DYN(&outbuf, separator);
+	column += (int) strlen(src);
+    }
 }
 
 static void
-wrap_concat(const char *src)
+wrap_concat1(const char *src)
 {
-    size_t need = strlen(src);
-    size_t want = strlen(separator) + need;
+    int need = (int) strlen(src);
+    wrap_concat(src, need, w1ST | wEND);
+}
 
-    if (column > INDENT
-	&& column + (int) want > width) {
-	force_wrap();
-    }
-    strcpy_DYN(&outbuf, src);
-    strcpy_DYN(&outbuf, separator);
-    column += (int) need;
+static void
+wrap_concat3(const char *name, const char *eqls, const char *value)
+{
+    int nlen = (int) strlen(name);
+    int elen = (int) strlen(eqls);
+    int vlen = (int) strlen(value);
+
+    wrap_concat(name, nlen + elen + vlen, w1ST);
+    wrap_concat(eqls, elen + vlen, w2ND);
+    wrap_concat(value, vlen, wEND);
 }
 
 #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
@@ -474,8 +720,35 @@
 	strncpy_DYN(buffer, "\t", (size_t) 1);
 }
 
+/*
+ * Check if the current line which was begun consists only of a tab and the
+ * given leading text.
+ */
+static bool
+leading_DYN(DYNBUF * buffer, const char *leading)
+{
+    bool result = FALSE;
+    size_t need = strlen(leading);
+    if (buffer->used > need) {
+	need = buffer->used - need;
+	if (!strcmp(buffer->text + need, leading)) {
+	    result = TRUE;
+	    while (--need != 0) {
+		if (buffer->text[need] == '\n') {
+		    break;
+		}
+		if (buffer->text[need] != '\t') {
+		    result = FALSE;
+		    break;
+		}
+	    }
+	}
+    }
+    return result;
+}
+
 bool
-has_params(const char *src)
+has_params(const char *src, bool formatting)
 {
     bool result = FALSE;
     int len = (int) strlen(src);
@@ -493,19 +766,27 @@
 	}
     }
     if (!ifthen) {
-	result = ((len > 50) && params);
+	if (formatting) {
+	    result = ((len > 50) && params);
+	} else {
+	    result = params;
+	}
     }
     return result;
 }
 
 static char *
-fmt_complex(TERMTYPE *tterm, const char *capability, char *src, int level)
+fmt_complex(TERMTYPE2 *tterm, const char *capability, char *src, int level)
 {
     bool percent = FALSE;
-    bool params = has_params(src);
+    bool params = has_params(src, TRUE);
 
     while (*src != '\0') {
 	switch (*src) {
+	case '^':
+	    percent = FALSE;
+	    strncpy_DYN(&tmpbuf, src++, (size_t) 1);
+	    break;
 	case '\\':
 	    percent = FALSE;
 	    strncpy_DYN(&tmpbuf, src++, (size_t) 1);
@@ -525,7 +806,7 @@
 		    strncpy_DYN(&tmpbuf, "%", (size_t) 1);
 		    strncpy_DYN(&tmpbuf, src, (size_t) 1);
 		    src++;
-		    params = has_params(src);
+		    params = has_params(src, TRUE);
 		    if (!params && *src != '\0' && *src != '%') {
 			strncpy_DYN(&tmpbuf, "\n", (size_t) 1);
 			indent_DYN(&tmpbuf, level + 1);
@@ -573,12 +854,11 @@
 	    }
 	    break;
 	case 'p':
-	    if (percent && params) {
+	    if (percent && params && !leading_DYN(&tmpbuf, "%")) {
 		tmpbuf.text[tmpbuf.used - 1] = '\n';
 		indent_DYN(&tmpbuf, level + 1);
 		strncpy_DYN(&tmpbuf, "%", (size_t) 1);
 	    }
-	    params = FALSE;
 	    percent = FALSE;
 	    break;
 	case ' ':
@@ -594,11 +874,38 @@
     return src;
 }
 
+/*
+ * Make "large" numbers a little easier to read by showing them in hexadecimal
+ * if they are "close" to a power of two.
+ */
+static const char *
+number_format(int value)
+{
+    const char *result = "%d";
+
+    if ((outform != F_TERMCAP) && (value > 255)) {
+	unsigned long lv = (unsigned long) value;
+	int bits = sizeof(unsigned long) * 8;
+	int nn;
+
+	for (nn = 8; nn < bits; ++nn) {
+	    unsigned long mm;
+
+	    mm = 1UL << nn;
+	    if ((mm - 16) <= lv && (mm + 16) > lv) {
+		result = "%#x";
+		break;
+	    }
+	}
+    }
+    return result;
+}
+
 #define SAME_CAP(n,cap) (&tterm->Strings[n] == &cap)
 #define EXTRA_CAP 20
 
 int
-fmt_entry(TERMTYPE *tterm,
+fmt_entry(TERMTYPE2 *tterm,
 	  PredFunc pred,
 	  int content_only,
 	  int suppress_untranslatable,
@@ -607,7 +914,6 @@
 {
     PredIdx i, j;
     char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
-    char *capability;
     NCURSES_CONST char *name;
     int predval, len;
     PredIdx num_bools = 0;
@@ -615,9 +921,8 @@
     PredIdx num_strings = 0;
     bool outcount = 0;
 
-#define WRAP_CONCAT	\
-	wrap_concat(buffer); \
-	outcount = TRUE
+#define WRAP_CONCAT1(s)		wrap_concat1(s); outcount = TRUE
+#define WRAP_CONCAT		WRAP_CONCAT1(buffer)
 
     len = 12;			/* terminfo file-header */
 
@@ -628,7 +933,7 @@
 
     strcpy_DYN(&outbuf, 0);
     if (content_only) {
-	column = INDENT;	/* FIXME: workaround to prevent empty lines */
+	column = indent;	/* workaround to prevent empty lines */
     } else {
 	strcpy_DYN(&outbuf, tterm->term_names);
 
@@ -671,7 +976,7 @@
 	}
     }
 
-    if (column != INDENT && height > 1)
+    if (column != indent && height > 1)
 	force_wrap();
 
     for_each_number(j, tterm) {
@@ -690,8 +995,13 @@
 		_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
 			    "%s@", name);
 	    } else {
+		size_t nn;
 		_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
-			    "%s#%d", name, tterm->Numbers[i]);
+			    "%s#", name);
+		nn = strlen(buffer);
+		_nc_SPRINTF(buffer + nn, _nc_SLIMIT(sizeof(buffer) - nn)
+			    number_format(tterm->Numbers[i]),
+			    tterm->Numbers[i]);
 		if (i + 1 > num_values)
 		    num_values = i + 1;
 	    }
@@ -699,7 +1009,7 @@
 	}
     }
 
-    if (column != INDENT && height > 1)
+    if (column != indent && height > 1)
 	force_wrap();
 
     len += (int) (num_bools
@@ -711,18 +1021,19 @@
 #undef CUR
 #define CUR tterm->
     if (outform == F_TERMCAP) {
-	if (termcap_reset != ABSENT_STRING) {
-	    if (init_3string != ABSENT_STRING
+	if (VALID_STRING(termcap_reset)) {
+	    if (VALID_STRING(init_3string)
 		&& !strcmp(init_3string, termcap_reset))
 		DISCARD(init_3string);
 
-	    if (reset_2string != ABSENT_STRING
+	    if (VALID_STRING(reset_2string)
 		&& !strcmp(reset_2string, termcap_reset))
 		DISCARD(reset_2string);
 	}
     }
 
     for_each_string(j, tterm) {
+	char *capability;
 	i = StrIndirect(j);
 	name = ExtStrname(tterm, (int) i, str_names);
 	assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
@@ -776,9 +1087,9 @@
 		    set_attributes = save_sgr;
 
 		    trimmed_sgr0 = _nc_trim_sgr0(tterm);
-		    if (strcmp(capability, trimmed_sgr0))
+		    if (strcmp(capability, trimmed_sgr0)) {
 			capability = trimmed_sgr0;
-		    else {
+		    } else {
 			if (trimmed_sgr0 != exit_attribute_mode)
 			    free(trimmed_sgr0);
 		    }
@@ -792,7 +1103,7 @@
 	buffer[0] = '\0';
 
 	if (predval != FAIL) {
-	    if (capability != ABSENT_STRING
+	    if (VALID_STRING(capability)
 		&& i + 1 > num_strings)
 		num_strings = i + 1;
 
@@ -800,14 +1111,13 @@
 		_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
 			    "%s@", name);
 		WRAP_CONCAT;
-	    } else if (outform == F_TERMCAP || outform == F_TCONVERR) {
+	    } else if (TcOutput()) {
 		char *srccap = _nc_tic_expand(capability, TRUE, numbers);
-		int params = (((i < (int) SIZEOF(parametrized)) &&
-			       (i < STRCOUNT))
+		int params = ((i < (int) SIZEOF(parametrized))
 			      ? parametrized[i]
 			      : ((*srccap == 'k')
 				 ? 0
-				 : has_params(srccap)));
+				 : has_params(srccap, FALSE)));
 		char *cv = _nc_infotocap(name, srccap, params);
 
 		if (cv == 0) {
@@ -815,28 +1125,45 @@
 			_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
 				    "%s=!!! %s WILL NOT CONVERT !!!",
 				    name, srccap);
+			WRAP_CONCAT;
 		    } else if (suppress_untranslatable) {
 			continue;
 		    } else {
 			char *s = srccap, *d = buffer;
-			_nc_SPRINTF(d, _nc_SLIMIT(sizeof(buffer)) "..%s=", name);
-			d += strlen(d);
+			int need = 3 + (int) strlen(name);
 			while ((*d = *s++) != 0) {
+			    if ((d - buffer + 2) >= (int) sizeof(buffer)) {
+				fprintf(stderr,
+					"%s: value for %s is too long\n",
+					_nc_progname,
+					name);
+				*d = '\0';
+				break;
+			    }
 			    if (*d == ':') {
 				*d++ = '\\';
 				*d = ':';
 			    } else if (*d == '\\') {
-				*++d = *s++;
+				if ((*++d = *s++) == '\0')
+				    break;
 			    }
 			    d++;
+			    *d = '\0';
 			}
+			need += (int) (d - buffer);
+			wrap_concat("..", need, w1ST | wERR);
+			need -= 2;
+			wrap_concat(name, need, wOFF | wERR);
+			need -= (int) strlen(name);
+			wrap_concat("=", need, w2ND | wERR);
+			need -= 1;
+			wrap_concat(buffer, need, wEND | wERR);
+			outcount = TRUE;
 		    }
 		} else {
-		    _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
-				"%s=%s", name, cv);
+		    wrap_concat3(name, "=", cv);
 		}
 		len += (int) strlen(capability) + 1;
-		WRAP_CONCAT;
 	    } else {
 		char *src = _nc_tic_expand(capability,
 					   outform == F_TERMINFO, numbers);
@@ -852,13 +1179,11 @@
 		    strcpy_DYN(&tmpbuf, src);
 		}
 		len += (int) strlen(capability) + 1;
-		wrap_concat(tmpbuf.text);
-		outcount = TRUE;
+		WRAP_CONCAT1(tmpbuf.text);
 	    }
 	}
 	/* e.g., trimmed_sgr0 */
-	if (capability != ABSENT_STRING &&
-	    capability != CANCELLED_STRING &&
+	if (VALID_STRING(capability) &&
 	    capability != tterm->Strings[i])
 	    free(capability);
     }
@@ -947,9 +1272,11 @@
     if (outcount) {
 	bool trimmed = FALSE;
 	j = (PredIdx) outbuf.used;
-	if (j >= 2
-	    && outbuf.text[j - 1] == '\t'
-	    && outbuf.text[j - 2] == '\n') {
+	if (wrapped && did_wrap) {
+	    /* EMPTY */ ;
+	} else if (j >= 2
+		   && outbuf.text[j - 1] == '\t'
+		   && outbuf.text[j - 2] == '\n') {
 	    outbuf.used -= 2;
 	    trimmed = TRUE;
 	} else if (j >= 4
@@ -984,7 +1311,7 @@
 }
 
 static bool
-kill_string(TERMTYPE *tterm, char *cap)
+kill_string(TERMTYPE2 *tterm, const char *const cap)
 {
     unsigned n;
     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
@@ -997,7 +1324,7 @@
 }
 
 static char *
-find_string(TERMTYPE *tterm, char *name)
+find_string(TERMTYPE2 *tterm, char *name)
 {
     PredIdx n;
     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
@@ -1018,16 +1345,18 @@
  * make it smaller.
  */
 static int
-kill_labels(TERMTYPE *tterm, int target)
+kill_labels(TERMTYPE2 *tterm, int target)
 {
     int n;
     int result = 0;
-    char *cap;
-    char name[10];
+    char name[20];
 
     for (n = 0; n <= 10; ++n) {
+	char *cap;
+
 	_nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "lf%d", n);
-	if ((cap = find_string(tterm, name)) != ABSENT_STRING
+	cap = find_string(tterm, name);
+	if (VALID_STRING(cap)
 	    && kill_string(tterm, cap)) {
 	    target -= (int) (strlen(cap) + 5);
 	    ++result;
@@ -1043,16 +1372,18 @@
  * make it smaller.
  */
 static int
-kill_fkeys(TERMTYPE *tterm, int target)
+kill_fkeys(TERMTYPE2 *tterm, int target)
 {
     int n;
     int result = 0;
-    char *cap;
-    char name[10];
+    char name[20];
 
     for (n = 60; n >= 0; --n) {
+	char *cap;
+
 	_nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "kf%d", n);
-	if ((cap = find_string(tterm, name)) != ABSENT_STRING
+	cap = find_string(tterm, name);
+	if (VALID_STRING(cap)
 	    && kill_string(tterm, cap)) {
 	    target -= (int) (strlen(cap) + 5);
 	    ++result;
@@ -1074,9 +1405,9 @@
 {
     bool result = TRUE;
 
-    if (mapping != ABSENT_STRING) {
+    if (VALID_STRING(mapping)) {
 	int n = 0;
-	while (mapping[n] != '\0') {
+	while (mapping[n] != '\0' && mapping[n + 1] != '\0') {
 	    if (isLine(mapping[n]) &&
 		mapping[n] != mapping[n + 1]) {
 		result = FALSE;
@@ -1097,7 +1428,7 @@
 #define SHOW_WHY PRINTF
 
 static bool
-purged_acs(TERMTYPE *tterm)
+purged_acs(TERMTYPE2 *tterm)
 {
     bool result = FALSE;
 
@@ -1112,22 +1443,103 @@
     return result;
 }
 
+static void
+encode_b64(char *target, char *source, unsigned state, int *saved)
+{
+    /* RFC-4648 */
+    static const char data[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "abcdefghijklmnopqrstuvwxyz"
+    "0123456789" "-_";
+    int ch = UChar(source[state]);
+
+    switch (state % 3) {
+    case 0:
+	*target++ = data[(ch >> 2) & 077];
+	*saved = (ch << 4);
+	break;
+    case 1:
+	*target++ = data[((ch >> 4) | *saved) & 077];
+	*saved = (ch << 2);
+	break;
+    case 2:
+	*target++ = data[((ch >> 6) | *saved) & 077];
+	*target++ = data[ch & 077];
+	*saved = 0;
+	break;
+    }
+    *target = '\0';
+}
+
 /*
  * Dump a single entry.
  */
 void
-dump_entry(TERMTYPE *tterm,
+dump_entry(TERMTYPE2 *tterm,
 	   int suppress_untranslatable,
 	   int limited,
 	   int numbers,
 	   PredFunc pred)
 {
-    TERMTYPE save_tterm;
-    int len, critlen;
+    TERMTYPE2 save_tterm;
+    int critlen;
     const char *legend;
     bool infodump;
 
-    if (outform == F_TERMCAP || outform == F_TCONVERR) {
+    if (quickdump) {
+	char bigbuf[65536];
+	unsigned offset = 0;
+
+	separator = "";
+	trailer = "\n";
+	indent = 0;
+
+	if (_nc_write_object(tterm, bigbuf, &offset, sizeof(bigbuf)) == OK) {
+	    char numbuf[80];
+	    unsigned n;
+
+	    if (quickdump & 1) {
+		if (outbuf.used)
+		    wrap_concat1("\n");
+		wrap_concat1("hex:");
+		for (n = 0; n < offset; ++n) {
+		    _nc_SPRINTF(numbuf, _nc_SLIMIT(sizeof(numbuf))
+				"%02X", UChar(bigbuf[n]));
+		    wrap_concat1(numbuf);
+		}
+	    }
+	    if (quickdump & 2) {
+		static char padding[] =
+		{0, 0};
+		int value = 0;
+
+		if (outbuf.used)
+		    wrap_concat1("\n");
+		wrap_concat1("b64:");
+		for (n = 0; n < offset; ++n) {
+		    encode_b64(numbuf, bigbuf, n, &value);
+		    wrap_concat1(numbuf);
+		}
+		switch (n % 3) {
+		case 0:
+		    break;
+		case 1:
+		    encode_b64(numbuf, padding, 1, &value);
+		    wrap_concat1(numbuf);
+		    wrap_concat1("==");
+		    break;
+		case 2:
+		    encode_b64(numbuf, padding, 1, &value);
+		    wrap_concat1(numbuf);
+		    wrap_concat1("=");
+		    break;
+		}
+	    }
+	}
+	return;
+    }
+
+    if (TcOutput()) {
 	critlen = MAX_TERMCAP_LENGTH;
 	legend = "older termcap";
 	infodump = FALSE;
@@ -1141,6 +1553,7 @@
     save_sgr = set_attributes;
 
     if ((FMT_ENTRY() > critlen)
+	&& TcOutput()
 	&& limited) {
 
 	save_tterm = *tterm;
@@ -1151,7 +1564,7 @@
 	}
 	if (FMT_ENTRY() > critlen) {
 	    /*
-	     * We pick on sgr because it's a nice long string capability that
+	     * We pick on sgr because it is a nice long string capability that
 	     * is really just an optimization hack.  Another good candidate is
 	     * acsc since it is both long and unused by BSD termcap.
 	     */
@@ -1196,6 +1609,7 @@
 	    }
 	    if (!changed || (FMT_ENTRY() > critlen)) {
 		int oldversion = tversion;
+		int len;
 
 		tversion = V_BSD;
 		SHOW_WHY("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
@@ -1216,7 +1630,8 @@
 		}
 		if (len > critlen) {
 		    (void) fprintf(stderr,
-				   "warning: %s entry is %d bytes long\n",
+				   "%s: %s entry is %d bytes long\n",
+				   _nc_progname,
 				   _nc_first_name(tterm->term_names),
 				   len);
 		    SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
@@ -1237,16 +1652,26 @@
 }
 
 void
-dump_uses(const char *name, bool infodump)
+dump_uses(const char *value, bool infodump)
 /* dump "use=" clauses in the appropriate format */
 {
-    char buffer[MAX_TERMINFO_LENGTH];
+    char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
+    int limit = (VALID_STRING(value) ? (int) strlen(value) : 0);
+    const char *cap = infodump ? "use" : "tc";
 
-    if (outform == F_TERMCAP || outform == F_TCONVERR)
+    if (TcOutput())
 	trim_trailing();
+    if (limit == 0) {
+	_nc_warning("empty \"%s\" field", cap);
+	value = "";
+    } else if (limit > MAX_ALIAS) {
+	_nc_warning("\"%s\" field too long (%d), limit to %d",
+		    cap, limit, MAX_ALIAS);
+	limit = MAX_ALIAS;
+    }
     _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
-		"%s%s", infodump ? "use=" : "tc=", name);
-    wrap_concat(buffer);
+		"%s=%.*s", cap, limit, value);
+    wrap_concat1(buffer);
 }
 
 int
@@ -1256,7 +1681,7 @@
      * Trim any remaining whitespace.
      */
     if (outbuf.used != 0) {
-	bool infodump = (outform != F_TERMCAP && outform != F_TCONVERR);
+	bool infodump = !TcOutput();
 	char delim = (char) (infodump ? ',' : ':');
 	int j;
 
@@ -1268,7 +1693,7 @@
 		outbuf.used = (size_t) j;
 	    } else if (!infodump && ch == '\\') {
 		outbuf.used = (size_t) j;
-	    } else if (ch == delim && (j == 0 || outbuf.text[j - 1] != '\\')) {
+	    } else if (ch == delim && (outbuf.text[j - 1] != '\\')) {
 		outbuf.used = (size_t) (j + 1);
 	    } else {
 		break;
@@ -1276,14 +1701,16 @@
 	}
 	outbuf.text[outbuf.used] = '\0';
     }
-    (void) fputs(outbuf.text, stdout);
-    putchar('\n');
+    if (outbuf.text != 0) {
+	(void) fputs(outbuf.text, stdout);
+	putchar('\n');
+    }
     return (int) outbuf.used;
 }
 
 void
 compare_entry(PredHook hook,
-	      TERMTYPE *tp GCC_UNUSED,
+	      TERMTYPE2 *tp GCC_UNUSED,
 	      bool quiet)
 /* compare two entries */
 {
@@ -1342,7 +1769,7 @@
 #define CUR tp->
 
 static void
-set_obsolete_termcaps(TERMTYPE *tp)
+set_obsolete_termcaps(TERMTYPE2 *tp)
 {
 #include "capdefaults.c"
 }
@@ -1352,12 +1779,11 @@
  * unique.
  */
 void
-repair_acsc(TERMTYPE *tp)
+repair_acsc(TERMTYPE2 *tp)
 {
     if (VALID_STRING(acs_chars)) {
-	size_t n, m;
+	size_t n;
 	char mapped[256];
-	char extra = 0;
 	unsigned source;
 	unsigned target;
 	bool fix_needed = FALSE;
@@ -1372,7 +1798,11 @@
 	    if (acs_chars[n + 1])
 		n++;
 	}
+
 	if (fix_needed) {
+	    size_t m;
+	    char extra = 0;
+
 	    memset(mapped, 0, sizeof(mapped));
 	    for (n = 0; acs_chars[n] != 0; n++) {
 		source = UChar(acs_chars[n]);