+ for (n = 0; n < level; n++)
+ strncpy_DYN(buffer, "\t", (size_t) 1);
+}
+
+bool
+has_params(const char *src)
+{
+ bool result = FALSE;
+ int len = (int) strlen(src);
+ int n;
+ bool ifthen = FALSE;
+ bool params = FALSE;
+
+ for (n = 0; n < len - 1; ++n) {
+ if (!strncmp(src + n, "%p", (size_t) 2)) {
+ params = TRUE;
+ } else if (!strncmp(src + n, "%;", (size_t) 2)) {
+ ifthen = TRUE;
+ result = params;
+ break;
+ }
+ }
+ if (!ifthen) {
+ result = ((len > 50) && params);
+ }
+ return result;
+}
+
+static char *
+fmt_complex(TERMTYPE2 *tterm, const char *capability, char *src, int level)
+{
+ bool percent = FALSE;
+ bool params = has_params(src);
+
+ 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);
+ break;
+ case '%':
+ percent = TRUE;
+ break;
+ case '?': /* "if" */
+ case 't': /* "then" */
+ case 'e': /* "else" */
+ if (percent) {
+ percent = FALSE;
+ tmpbuf.text[tmpbuf.used - 1] = '\n';
+ /* treat a "%e" as else-if, on the same level */
+ if (*src == 'e') {
+ indent_DYN(&tmpbuf, level);
+ strncpy_DYN(&tmpbuf, "%", (size_t) 1);
+ strncpy_DYN(&tmpbuf, src, (size_t) 1);
+ src++;
+ params = has_params(src);
+ if (!params && *src != '\0' && *src != '%') {
+ strncpy_DYN(&tmpbuf, "\n", (size_t) 1);
+ indent_DYN(&tmpbuf, level + 1);
+ }
+ } else {
+ indent_DYN(&tmpbuf, level + 1);
+ strncpy_DYN(&tmpbuf, "%", (size_t) 1);
+ strncpy_DYN(&tmpbuf, src, (size_t) 1);
+ if (*src++ == '?') {
+ src = fmt_complex(tterm, capability, src, level + 1);
+ if (*src != '\0' && *src != '%') {
+ strncpy_DYN(&tmpbuf, "\n", (size_t) 1);
+ indent_DYN(&tmpbuf, level + 1);
+ }
+ } else if (level == 1) {
+ if (checking)
+ _nc_warning("%s: %%%c without %%? in %s",
+ _nc_first_name(tterm->term_names),
+ *src, capability);
+ }
+ }
+ continue;
+ }
+ break;
+ case ';': /* "endif" */
+ if (percent) {
+ percent = FALSE;
+ if (level > 1) {
+ tmpbuf.text[tmpbuf.used - 1] = '\n';
+ indent_DYN(&tmpbuf, level);
+ strncpy_DYN(&tmpbuf, "%", (size_t) 1);
+ strncpy_DYN(&tmpbuf, src++, (size_t) 1);
+ if (src[0] == '%'
+ && src[1] != '\0'
+ && (strchr("?e;", src[1])) == 0) {
+ tmpbuf.text[tmpbuf.used++] = '\n';
+ indent_DYN(&tmpbuf, level);
+ }
+ return src;
+ }
+ if (checking)
+ _nc_warning("%s: %%; without %%? in %s",
+ _nc_first_name(tterm->term_names),
+ capability);
+ }
+ break;
+ case 'p':
+ if (percent && params) {
+ tmpbuf.text[tmpbuf.used - 1] = '\n';
+ indent_DYN(&tmpbuf, level + 1);
+ strncpy_DYN(&tmpbuf, "%", (size_t) 1);
+ }
+ params = FALSE;
+ percent = FALSE;
+ break;
+ case ' ':
+ strncpy_DYN(&tmpbuf, "\\s", (size_t) 2);
+ ++src;
+ continue;
+ default:
+ percent = FALSE;
+ break;
+ }
+ strncpy_DYN(&tmpbuf, src++, (size_t) 1);
+ }
+ 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;
+ unsigned long mm;
+ int bits = sizeof(unsigned long) * 8;
+ int nn;
+ for (nn = 8; nn < bits; ++nn) {
+ 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(TERMTYPE2 *tterm,
+ PredFunc pred,
+ int content_only,
+ int suppress_untranslatable,
+ int infodump,
+ int numbers)
+{
+ PredIdx i, j;
+ char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
+ char *capability;
+ NCURSES_CONST char *name;
+ int predval, len;
+ PredIdx num_bools = 0;
+ PredIdx num_values = 0;
+ PredIdx num_strings = 0;
+ bool outcount = 0;
+
+#define WRAP_CONCAT1(s) wrap_concat(s); outcount = TRUE
+#define WRAP_CONCAT2(a,b) wrap_concat(a); WRAP_CONCAT1(b)
+#define WRAP_CONCAT3(a,b,c) wrap_concat(a); WRAP_CONCAT2(b,c)
+#define WRAP_CONCAT WRAP_CONCAT1(buffer)