X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=progs%2Fdump_entry.c;h=3be09f8671cbb44cd0eb862357944798d657f5de;hp=65de9f9bc1f10f9c648e1341075789a0c81a824b;hb=048a1c1a65c6d98d92fca97f8d175d10d21091d0;hpb=cc387b11f421650091d84640e05825ea5161ac66 diff --git a/progs/dump_entry.c b/progs/dump_entry.c index 65de9f9b..3be09f86 100644 --- a/progs/dump_entry.c +++ b/progs/dump_entry.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998-2012,2013 Free Software Foundation, Inc. * + * Copyright (c) 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 * @@ -39,13 +39,14 @@ #include "termsort.c" /* this C file is generated */ #include /* so is this */ -MODULE_ID("$Id: dump_entry.c,v 1.111 2013/12/15 01:05:20 tom Exp $") +MODULE_ID("$Id: dump_entry.c,v 1.148 2017/02/04 16:55:42 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,6 +62,10 @@ 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 */ static char *save_sgr; @@ -74,6 +79,7 @@ static NCURSES_CONST char *const *num_names; 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) */ @@ -119,7 +125,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; } @@ -155,17 +161,17 @@ _nc_leaks_dump_entry(void) #endif #define NameTrans(check,result) \ - if (OkIndex(np->nte_index, check) \ + if ((np->nte_index <= OK_ ## check) \ && check[np->nte_index]) \ return (result[np->nte_index]) NCURSES_CONST char * nametrans(const char *name) -/* translate a capability name from termcap to terminfo */ +/* translate a capability name to termcap from terminfo */ { const struct name_table_entry *np; - if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) + if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) { switch (np->nte_type) { case BOOLEAN: NameTrans(bool_from_termcap, boolcodes); @@ -179,6 +185,7 @@ nametrans(const char *name) NameTrans(str_from_termcap, strcodes); break; } + } return (0); } @@ -187,15 +194,23 @@ void dump_init(const char *version, int mode, int sort, + bool wrap_strings, int twidth, int theight, unsigned traceval, - bool formatted) + bool formatted, + 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) @@ -240,6 +255,7 @@ dump_init(const char *version, trailer = "\\\n\t:"; break; } + indent = 8; /* implement sort modes */ switch (sortmode = sort) { @@ -409,22 +425,208 @@ force_wrap(void) oldcol = column; trim_trailing(); strcpy_DYN(&outbuf, trailer); - column = INDENT; + column = indent; +} + +static int +op_length(const char *src, int offset) +{ + int result = 0; + int ch; + if (offset > 0 && src[offset - 1] == '\\') { + result = 0; + } else { + 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; + int n; + if (size > 0) { + /* check if that would split a backslash-sequence */ + int mark = size; + 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; + int s, d; + for (pass = 0; pass < 2; ++pass) { + for (s = d = 0; src[s] != '\0'; ++s) { + if (src[s] == ' ') { + if (pass) { + strcpy(&result[d], fill); + d += (int) size; + } else { + need += size; + } + } else { + if (pass) { + result[d++] = src[s]; + } else { + ++d; + } + } + } + if (pass) { + result[d] = '\0'; + } else { + result = malloc(need + 1); + if (result == 0) + failed("fill_spaces"); + } + } + return result; } static void wrap_concat(const char *src) { - size_t need = strlen(src); - size_t want = strlen(separator) + need; + int need = (int) strlen(src); + int gaps = (int) strlen(separator); + int want = gaps + need; - if (column > INDENT - && column + (int) want > width) { + did_wrap = (width <= 0); + if (column > indent + && column + want > width) { force_wrap(); } - strcpy_DYN(&outbuf, src); - strcpy_DYN(&outbuf, separator); - column += (int) need; + if (wrapped && + (width >= 0) && + (column + want) > width && + (!TcOutput() || strncmp(src, "..", 2))) { + int step = 0; + int used = width > WRAPPED ? width : WRAPPED; + int size = used; + 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 ((p = strchr(fill, '=')) != 0) { + base = (int) (p + 1 - fill); + 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) { + while ((column + (need + gaps)) > used) { + size = used; + 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; + } + } + } + if (need > 0) { + if (step) + strcpy_DYN(&outbuf, align); + strcpy_DYN(&outbuf, fill + step); + } + strcpy_DYN(&outbuf, separator); + trailer = my_t; + force_wrap(); + + free(fill); + } else { + strcpy_DYN(&outbuf, src); + strcpy_DYN(&outbuf, separator); + column += need; + } } #define IGNORE_SEP_TRAIL(first,last,sep_trail) \ @@ -470,7 +672,7 @@ indent_DYN(DYNBUF * buffer, int level) strncpy_DYN(buffer, "\t", (size_t) 1); } -static bool +bool has_params(const char *src) { bool result = FALSE; @@ -502,6 +704,10 @@ fmt_complex(TERMTYPE *tterm, const char *capability, char *src, int level) 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); @@ -537,9 +743,10 @@ fmt_complex(TERMTYPE *tterm, const char *capability, char *src, int level) indent_DYN(&tmpbuf, level + 1); } } else if (level == 1) { - _nc_warning("%s: %%%c without %%? in %s", - _nc_first_name(tterm->term_names), - *src, capability); + if (checking) + _nc_warning("%s: %%%c without %%? in %s", + _nc_first_name(tterm->term_names), + *src, capability); } } continue; @@ -561,9 +768,10 @@ fmt_complex(TERMTYPE *tterm, const char *capability, char *src, int level) } return src; } - _nc_warning("%s: %%; without %%? in %s", - _nc_first_name(tterm->term_names), - capability); + if (checking) + _nc_warning("%s: %%; without %%? in %s", + _nc_first_name(tterm->term_names), + capability); } break; case 'p': @@ -622,7 +830,7 @@ fmt_entry(TERMTYPE *tterm, strcpy_DYN(&outbuf, 0); if (content_only) { - column = INDENT; /* FIXME: workaround to prevent empty lines */ + column = indent; /* FIXME: workaround to prevent empty lines */ } else { strcpy_DYN(&outbuf, tterm->term_names); @@ -665,7 +873,7 @@ fmt_entry(TERMTYPE *tterm, } } - if (column != INDENT && height > 1) + if (column != indent && height > 1) force_wrap(); for_each_number(j, tterm) { @@ -693,7 +901,7 @@ fmt_entry(TERMTYPE *tterm, } } - if (column != INDENT && height > 1) + if (column != indent && height > 1) force_wrap(); len += (int) (num_bools @@ -772,6 +980,10 @@ fmt_entry(TERMTYPE *tterm, trimmed_sgr0 = _nc_trim_sgr0(tterm); if (strcmp(capability, trimmed_sgr0)) capability = trimmed_sgr0; + else { + if (trimmed_sgr0 != exit_attribute_mode) + free(trimmed_sgr0); + } set_attributes = my_sgr; } @@ -790,11 +1002,14 @@ fmt_entry(TERMTYPE *tterm, _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) "%s@", name); WRAP_CONCAT; - } else if (outform == F_TERMCAP || outform == F_TCONVERR) { - int params = ((i < (int) SIZEOF(parametrized)) - ? parametrized[i] - : 0); + } else if (TcOutput()) { char *srccap = _nc_tic_expand(capability, TRUE, numbers); + int params = (((i < (int) SIZEOF(parametrized)) && + (i < STRCOUNT)) + ? parametrized[i] + : ((*srccap == 'k') + ? 0 + : has_params(srccap))); char *cv = _nc_infotocap(name, srccap, params); if (cv == 0) { @@ -934,9 +1149,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 @@ -1099,6 +1316,34 @@ purged_acs(TERMTYPE *tterm) 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. */ @@ -1114,7 +1359,56 @@ dump_entry(TERMTYPE *tterm, const char *legend; bool infodump; - if (outform == F_TERMCAP || outform == F_TCONVERR) { + 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]; + if (quickdump & 1) { + if (outbuf.used) + wrap_concat("\n"); + wrap_concat("hex:"); + for (n = 0; n < offset; ++n) { + _nc_SPRINTF(numbuf, _nc_SLIMIT(sizeof(numbuf)) + "%02X", UChar(bigbuf[n])); + wrap_concat(numbuf); + } + } + if (quickdump & 2) { + static char padding[] = + {0, 0}; + int value = 0; + if (outbuf.used) + wrap_concat("\n"); + wrap_concat("b64:"); + for (n = 0; n < offset; ++n) { + encode_b64(numbuf, bigbuf, n, &value); + wrap_concat(numbuf); + } + switch (n % 3) { + case 0: + break; + case 1: + encode_b64(numbuf, padding, 1, &value); + wrap_concat(numbuf); + wrap_concat("=="); + break; + case 2: + encode_b64(numbuf, padding, 1, &value); + wrap_concat(numbuf); + wrap_concat("="); + break; + } + } + } + return; + } + + if (TcOutput()) { critlen = MAX_TERMCAP_LENGTH; legend = "older termcap"; infodump = FALSE; @@ -1229,7 +1523,7 @@ dump_uses(const char *name, bool infodump) { char buffer[MAX_TERMINFO_LENGTH]; - if (outform == F_TERMCAP || outform == F_TCONVERR) + if (TcOutput()) trim_trailing(); _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) "%s%s", infodump ? "use=" : "tc=", name); @@ -1243,7 +1537,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; @@ -1263,8 +1557,10 @@ show_entry(void) } 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; }