X-Git-Url: http://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=progs%2Fdump_entry.c;h=be332d2e7765c28cd4082329bff1620c19dfd704;hp=19d6cde72a233e7648acb78807bce2be2033982b;hb=HEAD;hpb=a3725e39272393790e32a083fd7391aad607828d diff --git a/progs/dump_entry.c b/progs/dump_entry.c index 19d6cde7..be332d2e 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,16 +36,18 @@ #define __INTERNAL_CAPS_VISIBLE #include -#include "dump_entry.h" -#include "termsort.c" /* this C file is generated */ +#include +#include /* this C file is generated */ #include /* so is this */ -MODULE_ID("$Id: dump_entry.c,v 1.123 2015/09/05 23:31:12 tom Exp $") +MODULE_ID("$Id: dump_entry.c,v 1.196 2023/05/27 20:13:10 tom Exp $") #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; @@ -60,6 +63,8 @@ static int height = 65535; /* max number of lines for listings */ 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 */ @@ -80,7 +85,7 @@ 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 */ @@ -90,7 +95,7 @@ static int indent = 8; #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])) @@ -102,9 +107,7 @@ static int indent = 8; #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); @@ -121,7 +124,7 @@ strncpy_DYN(DYNBUF * dst, const char *src, size_t need) 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; } @@ -190,6 +193,7 @@ void dump_init(const char *version, int mode, int sort, + bool wrap_strings, int twidth, int theight, unsigned traceval, @@ -201,9 +205,12 @@ dump_init(const char *version, width = twidth; height = theight; pretty = formatted; + wrapped = wrap_strings; checking = check; quickdump = (quick & 3); + did_wrap = (width <= 0); + /* versions */ if (version == 0) tversion = V_ALLCAPS; @@ -291,7 +298,7 @@ dump_init(const char *version, _nc_progname, width, tversion, outform); } -static TERMTYPE *cur_type; +static TERMTYPE2 *cur_type; static int dump_predicate(PredType type, PredIdx idx) @@ -314,7 +321,7 @@ dump_predicate(PredType type, PredIdx idx) 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) \ @@ -420,19 +427,254 @@ force_wrap(void) column = indent; } -static void -wrap_concat(const char *src) +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 want = strlen(separator) + need; + 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) - if (column > indent - && column + (int) want > width) { +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(); } - strcpy_DYN(&outbuf, src); - strcpy_DYN(&outbuf, separator); - column += (int) need; + 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_concat1(const char *src) +{ + int need = (int) strlen(src); + wrap_concat(src, need, w1ST | wEND); +} + +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) \ @@ -478,8 +720,35 @@ indent_DYN(DYNBUF * buffer, int level) 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); @@ -497,19 +766,27 @@ has_params(const char *src) } } 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); @@ -529,7 +806,7 @@ fmt_complex(TERMTYPE *tterm, const char *capability, char *src, int level) 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); @@ -577,12 +854,11 @@ fmt_complex(TERMTYPE *tterm, const char *capability, char *src, int level) } 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 ' ': @@ -598,11 +874,38 @@ fmt_complex(TERMTYPE *tterm, const char *capability, char *src, int level) 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, @@ -611,7 +914,6 @@ fmt_entry(TERMTYPE *tterm, { PredIdx i, j; char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP]; - char *capability; NCURSES_CONST char *name; int predval, len; PredIdx num_bools = 0; @@ -619,9 +921,8 @@ fmt_entry(TERMTYPE *tterm, 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 */ @@ -632,7 +933,7 @@ fmt_entry(TERMTYPE *tterm, 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); @@ -694,8 +995,13 @@ fmt_entry(TERMTYPE *tterm, _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; } @@ -715,18 +1021,19 @@ fmt_entry(TERMTYPE *tterm, #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); @@ -780,9 +1087,9 @@ fmt_entry(TERMTYPE *tterm, 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); } @@ -796,7 +1103,7 @@ fmt_entry(TERMTYPE *tterm, buffer[0] = '\0'; if (predval != FAIL) { - if (capability != ABSENT_STRING + if (VALID_STRING(capability) && i + 1 > num_strings) num_strings = i + 1; @@ -804,14 +1111,13 @@ fmt_entry(TERMTYPE *tterm, _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) { @@ -819,28 +1125,45 @@ fmt_entry(TERMTYPE *tterm, _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); @@ -856,13 +1179,11 @@ fmt_entry(TERMTYPE *tterm, 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); } @@ -951,9 +1272,11 @@ fmt_entry(TERMTYPE *tterm, 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 @@ -988,7 +1311,7 @@ fmt_entry(TERMTYPE *tterm, } 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) { @@ -1001,7 +1324,7 @@ kill_string(TERMTYPE *tterm, char *cap) } static char * -find_string(TERMTYPE *tterm, char *name) +find_string(TERMTYPE2 *tterm, char *name) { PredIdx n; for (n = 0; n < NUM_STRINGS(tterm); ++n) { @@ -1022,16 +1345,18 @@ find_string(TERMTYPE *tterm, char *name) * 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; @@ -1047,16 +1372,18 @@ kill_labels(TERMTYPE *tterm, int target) * 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; @@ -1078,9 +1405,9 @@ one_one_mapping(const char *mapping) { 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; @@ -1101,7 +1428,7 @@ one_one_mapping(const char *mapping) #define SHOW_WHY PRINTF static bool -purged_acs(TERMTYPE *tterm) +purged_acs(TERMTYPE2 *tterm) { bool result = FALSE; @@ -1128,16 +1455,16 @@ encode_b64(char *target, char *source, unsigned state, int *saved) switch (state % 3) { case 0: - *target++ = data[ch & 077]; - *saved = (ch >> 6) & 3; + *target++ = data[(ch >> 2) & 077]; + *saved = (ch << 4); break; case 1: - *target++ = data[((ch << 2) | *saved) & 077]; - *saved = (ch >> 4) & 017; + *target++ = data[((ch >> 4) | *saved) & 077]; + *saved = (ch << 2); break; case 2: - *target++ = data[((ch << 4) | *saved) & 077]; - *target++ = data[(ch >> 2) & 077]; + *target++ = data[((ch >> 6) | *saved) & 077]; + *target++ = data[ch & 077]; *saved = 0; break; } @@ -1148,52 +1475,63 @@ encode_b64(char *target, char *source, unsigned state, int *saved) * 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 (quickdump) { char bigbuf[65536]; - unsigned n; 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_concat("\n"); - wrap_concat("hex:"); + wrap_concat1("\n"); + wrap_concat1("hex:"); for (n = 0; n < offset; ++n) { - sprintf(numbuf, "%02X", UChar(bigbuf[n])); - wrap_concat(numbuf); + _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_concat("\n"); - wrap_concat("b64:"); + wrap_concat1("\n"); + wrap_concat1("b64:"); for (n = 0; n < offset; ++n) { encode_b64(numbuf, bigbuf, n, &value); - wrap_concat(numbuf); + wrap_concat1(numbuf); } switch (n % 3) { case 0: break; case 1: - wrap_concat("==="); + encode_b64(numbuf, padding, 1, &value); + wrap_concat1(numbuf); + wrap_concat1("=="); break; case 2: - wrap_concat("=="); + encode_b64(numbuf, padding, 1, &value); + wrap_concat1(numbuf); + wrap_concat1("="); break; } } @@ -1201,7 +1539,7 @@ dump_entry(TERMTYPE *tterm, return; } - if (outform == F_TERMCAP || outform == F_TCONVERR) { + if (TcOutput()) { critlen = MAX_TERMCAP_LENGTH; legend = "older termcap"; infodump = FALSE; @@ -1215,6 +1553,7 @@ dump_entry(TERMTYPE *tterm, save_sgr = set_attributes; if ((FMT_ENTRY() > critlen) + && TcOutput() && limited) { save_tterm = *tterm; @@ -1225,7 +1564,7 @@ dump_entry(TERMTYPE *tterm, } 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. */ @@ -1270,6 +1609,7 @@ dump_entry(TERMTYPE *tterm, } 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", @@ -1290,7 +1630,8 @@ dump_entry(TERMTYPE *tterm, } 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", @@ -1311,16 +1652,26 @@ dump_entry(TERMTYPE *tterm, } 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 @@ -1330,7 +1681,7 @@ show_entry(void) * 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; @@ -1342,7 +1693,7 @@ show_entry(void) 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; @@ -1359,7 +1710,7 @@ show_entry(void) void compare_entry(PredHook hook, - TERMTYPE *tp GCC_UNUSED, + TERMTYPE2 *tp GCC_UNUSED, bool quiet) /* compare two entries */ { @@ -1418,7 +1769,7 @@ compare_entry(PredHook hook, #define CUR tp-> static void -set_obsolete_termcaps(TERMTYPE *tp) +set_obsolete_termcaps(TERMTYPE2 *tp) { #include "capdefaults.c" } @@ -1428,12 +1779,11 @@ set_obsolete_termcaps(TERMTYPE *tp) * 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; @@ -1448,7 +1798,11 @@ repair_acsc(TERMTYPE *tp) 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]);