1 /****************************************************************************
2 * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
31 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
32 * and: Thomas E. Dickey 1996 on *
33 ****************************************************************************/
35 #define __INTERNAL_CAPS_VISIBLE
36 #include <progs.priv.h>
38 #include "dump_entry.h"
39 #include "termsort.c" /* this C file is generated */
40 #include <parametrized.h> /* so is this */
42 MODULE_ID("$Id: dump_entry.c,v 1.123 2015/09/05 23:31:12 tom Exp $")
44 #define DISCARD(string) string = ABSENT_STRING
45 #define PRINTF (void) printf
47 #define OkIndex(index,array) ((int)(index) >= 0 && (int)(index) < (int) SIZEOF(array))
55 static int tversion; /* terminfo version */
56 static int outform; /* output format to use */
57 static int sortmode; /* sort mode to use */
58 static int width = 60; /* max line width for listings */
59 static int height = 65535; /* max number of lines for listings */
60 static int column; /* current column, limited by 'width' */
61 static int oldcol; /* last value of column before wrap */
62 static bool pretty; /* true if we format if-then-else strings */
63 static bool checking; /* true if we are checking for tic */
64 static int quickdump; /* true if we are dumping compiled data */
66 static char *save_sgr;
71 /* indirection pointers for implementing sort and display modes */
72 static const PredIdx *bool_indirect, *num_indirect, *str_indirect;
73 static NCURSES_CONST char *const *bool_names;
74 static NCURSES_CONST char *const *num_names;
75 static NCURSES_CONST char *const *str_names;
77 static const char *separator = "", *trailer = "";
78 static int indent = 8;
80 /* cover various ports and variants of terminfo */
81 #define V_ALLCAPS 0 /* all capabilities (SVr4, XSI, ncurses) */
82 #define V_SVR1 1 /* SVR1, Ultrix */
83 #define V_HPUX 2 /* HP/UX */
84 #define V_AIX 3 /* AIX */
85 #define V_BSD 4 /* BSD */
88 #define OBSOLETE(n) (!_nc_user_definable && (n[0] == 'O' && n[1] == 'T'))
90 #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
93 #define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && OBSOLETE(n))
96 #define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
97 #define NumIndirect(j) ((j >= NUMCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
98 #define StrIndirect(j) ((j >= STRCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
100 #define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
101 #define NumIndirect(j) ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
102 #define StrIndirect(j) ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
105 static void failed(const char *) GCC_NORETURN;
108 failed(const char *s)
111 ExitProgram(EXIT_FAILURE);
115 strncpy_DYN(DYNBUF * dst, const char *src, size_t need)
117 size_t want = need + dst->used + 1;
118 if (want > dst->size) {
119 dst->size += (want + 1024); /* be generous */
120 dst->text = typeRealloc(char, dst->size, dst->text);
122 failed("strncpy_DYN");
124 (void) strncpy(dst->text + dst->used, src, need);
126 dst->text[dst->used] = 0;
130 strcpy_DYN(DYNBUF * dst, const char *src)
136 strncpy_DYN(dst, src, strlen(src));
152 _nc_leaks_dump_entry(void)
159 #define NameTrans(check,result) \
160 if ((np->nte_index <= OK_ ## check) \
161 && check[np->nte_index]) \
162 return (result[np->nte_index])
165 nametrans(const char *name)
166 /* translate a capability name to termcap from terminfo */
168 const struct name_table_entry *np;
170 if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) {
171 switch (np->nte_type) {
173 NameTrans(bool_from_termcap, boolcodes);
177 NameTrans(num_from_termcap, numcodes);
181 NameTrans(str_from_termcap, strcodes);
190 dump_init(const char *version,
199 /* set up for entry display */
205 quickdump = (quick & 3);
209 tversion = V_ALLCAPS;
210 else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
211 || !strcmp(version, "Ultrix"))
213 else if (!strcmp(version, "HP"))
215 else if (!strcmp(version, "AIX"))
217 else if (!strcmp(version, "BSD"))
220 tversion = V_ALLCAPS;
222 /* implement display modes */
223 switch (outform = mode) {
226 bool_names = boolnames;
227 num_names = numnames;
228 str_names = strnames;
229 separator = (twidth > 0 && theight > 1) ? ", " : ",";
234 bool_names = boolfnames;
235 num_names = numfnames;
236 str_names = strfnames;
237 separator = (twidth > 0 && theight > 1) ? ", " : ",";
243 bool_names = boolcodes;
244 num_names = numcodes;
245 str_names = strcodes;
252 /* implement sort modes */
253 switch (sortmode = sort) {
256 (void) fprintf(stderr,
257 "%s: sorting by term structure order\n", _nc_progname);
262 (void) fprintf(stderr,
263 "%s: sorting by terminfo name order\n", _nc_progname);
264 bool_indirect = bool_terminfo_sort;
265 num_indirect = num_terminfo_sort;
266 str_indirect = str_terminfo_sort;
271 (void) fprintf(stderr,
272 "%s: sorting by C variable order\n", _nc_progname);
273 bool_indirect = bool_variable_sort;
274 num_indirect = num_variable_sort;
275 str_indirect = str_variable_sort;
280 (void) fprintf(stderr,
281 "%s: sorting by termcap name order\n", _nc_progname);
282 bool_indirect = bool_termcap_sort;
283 num_indirect = num_termcap_sort;
284 str_indirect = str_termcap_sort;
289 (void) fprintf(stderr,
290 "%s: width = %d, tversion = %d, outform = %d\n",
291 _nc_progname, width, tversion, outform);
294 static TERMTYPE *cur_type;
297 dump_predicate(PredType type, PredIdx idx)
298 /* predicate function to use for ordinary decompilation */
302 return (cur_type->Booleans[idx] == FALSE)
303 ? FAIL : cur_type->Booleans[idx];
306 return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
307 ? FAIL : cur_type->Numbers[idx];
310 return (cur_type->Strings[idx] != ABSENT_STRING)
314 return (FALSE); /* pacify compiler */
317 static void set_obsolete_termcaps(TERMTYPE *tp);
319 /* is this the index of a function key string? */
321 (((i) >= STR_IDX(key_f0) && \
322 (i) <= STR_IDX(key_f9)) || \
323 ((i) >= STR_IDX(key_f11) && \
324 (i) <= STR_IDX(key_f63)))
327 * If we configure with a different Caps file, the offsets into the arrays
328 * will change. So we use an address expression.
330 #define BOOL_IDX(name) (PredType) (&(name) - &(CUR Booleans[0]))
331 #define NUM_IDX(name) (PredType) (&(name) - &(CUR Numbers[0]))
332 #define STR_IDX(name) (PredType) (&(name) - &(CUR Strings[0]))
335 version_filter(PredType type, PredIdx idx)
336 /* filter out capabilities we may want to suppress */
339 case V_ALLCAPS: /* SVr4, XSI Curses */
342 case V_SVR1: /* System V Release 1, Ultrix */
345 return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
347 return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
349 return ((idx <= STR_IDX(prtr_non)) ? TRUE : FALSE);
353 case V_HPUX: /* Hewlett-Packard */
356 return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
358 return ((idx <= NUM_IDX(label_width)) ? TRUE : FALSE);
360 if (idx <= STR_IDX(prtr_non))
362 else if (FNKEY(idx)) /* function keys */
364 else if (idx == STR_IDX(plab_norm)
365 || idx == STR_IDX(label_on)
366 || idx == STR_IDX(label_off))
373 case V_AIX: /* AIX */
376 return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
378 return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
380 if (idx <= STR_IDX(prtr_non))
382 else if (FNKEY(idx)) /* function keys */
389 #define is_termcap(type) (OkIndex(idx, type##_from_termcap) && \
390 type##_from_termcap[idx])
392 case V_BSD: /* BSD */
395 return is_termcap(bool);
397 return is_termcap(num);
399 return is_termcap(str);
404 return (FALSE); /* pacify the compiler */
410 while (outbuf.used > 0 && outbuf.text[outbuf.used - 1] == ' ')
411 outbuf.text[--outbuf.used] = '\0';
419 strcpy_DYN(&outbuf, trailer);
424 wrap_concat(const char *src)
426 size_t need = strlen(src);
427 size_t want = strlen(separator) + need;
430 && column + (int) want > width) {
433 strcpy_DYN(&outbuf, src);
434 strcpy_DYN(&outbuf, separator);
435 column += (int) need;
438 #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
439 if ((size_t)(last - first) > sizeof(sep_trail)-1 \
440 && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
441 first += sizeof(sep_trail)-2
443 /* Returns the nominal length of the buffer assuming it is termcap format,
444 * i.e., the continuation sequence is treated as a single character ":".
446 * There are several implementations of termcap which read the text into a
447 * fixed-size buffer. Generally they strip the newlines from the text, but may
448 * not do it until after the buffer is read. Also, "tc=" resolution may be
449 * expanded in the same buffer. This function is useful for measuring the size
450 * of the best fixed-buffer implementation; the worst case may be much worse.
452 #ifdef TEST_TERMCAP_LENGTH
454 termcap_length(const char *src)
456 static const char pattern[] = ":\\\n\t:";
459 const char *const t = src + strlen(src);
461 while (*src != '\0') {
462 IGNORE_SEP_TRAIL(src, t, pattern);
469 #define termcap_length(src) strlen(src)
473 indent_DYN(DYNBUF * buffer, int level)
477 for (n = 0; n < level; n++)
478 strncpy_DYN(buffer, "\t", (size_t) 1);
482 has_params(const char *src)
485 int len = (int) strlen(src);
490 for (n = 0; n < len - 1; ++n) {
491 if (!strncmp(src + n, "%p", (size_t) 2)) {
493 } else if (!strncmp(src + n, "%;", (size_t) 2)) {
500 result = ((len > 50) && params);
506 fmt_complex(TERMTYPE *tterm, const char *capability, char *src, int level)
508 bool percent = FALSE;
509 bool params = has_params(src);
511 while (*src != '\0') {
515 strncpy_DYN(&tmpbuf, src++, (size_t) 1);
521 case 't': /* "then" */
522 case 'e': /* "else" */
525 tmpbuf.text[tmpbuf.used - 1] = '\n';
526 /* treat a "%e" as else-if, on the same level */
528 indent_DYN(&tmpbuf, level);
529 strncpy_DYN(&tmpbuf, "%", (size_t) 1);
530 strncpy_DYN(&tmpbuf, src, (size_t) 1);
532 params = has_params(src);
533 if (!params && *src != '\0' && *src != '%') {
534 strncpy_DYN(&tmpbuf, "\n", (size_t) 1);
535 indent_DYN(&tmpbuf, level + 1);
538 indent_DYN(&tmpbuf, level + 1);
539 strncpy_DYN(&tmpbuf, "%", (size_t) 1);
540 strncpy_DYN(&tmpbuf, src, (size_t) 1);
542 src = fmt_complex(tterm, capability, src, level + 1);
543 if (*src != '\0' && *src != '%') {
544 strncpy_DYN(&tmpbuf, "\n", (size_t) 1);
545 indent_DYN(&tmpbuf, level + 1);
547 } else if (level == 1) {
549 _nc_warning("%s: %%%c without %%? in %s",
550 _nc_first_name(tterm->term_names),
557 case ';': /* "endif" */
561 tmpbuf.text[tmpbuf.used - 1] = '\n';
562 indent_DYN(&tmpbuf, level);
563 strncpy_DYN(&tmpbuf, "%", (size_t) 1);
564 strncpy_DYN(&tmpbuf, src++, (size_t) 1);
567 && (strchr("?e;", src[1])) == 0) {
568 tmpbuf.text[tmpbuf.used++] = '\n';
569 indent_DYN(&tmpbuf, level);
574 _nc_warning("%s: %%; without %%? in %s",
575 _nc_first_name(tterm->term_names),
580 if (percent && params) {
581 tmpbuf.text[tmpbuf.used - 1] = '\n';
582 indent_DYN(&tmpbuf, level + 1);
583 strncpy_DYN(&tmpbuf, "%", (size_t) 1);
589 strncpy_DYN(&tmpbuf, "\\s", (size_t) 2);
596 strncpy_DYN(&tmpbuf, src++, (size_t) 1);
601 #define SAME_CAP(n,cap) (&tterm->Strings[n] == &cap)
605 fmt_entry(TERMTYPE *tterm,
608 int suppress_untranslatable,
613 char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
615 NCURSES_CONST char *name;
617 PredIdx num_bools = 0;
618 PredIdx num_values = 0;
619 PredIdx num_strings = 0;
622 #define WRAP_CONCAT \
623 wrap_concat(buffer); \
626 len = 12; /* terminfo file-header */
630 pred = dump_predicate;
633 strcpy_DYN(&outbuf, 0);
635 column = indent; /* FIXME: workaround to prevent empty lines */
637 strcpy_DYN(&outbuf, tterm->term_names);
640 * Colon is legal in terminfo descriptions, but not in termcap.
643 char *p = outbuf.text;
651 strcpy_DYN(&outbuf, separator);
652 column = (int) outbuf.used;
657 for_each_boolean(j, tterm) {
659 name = ExtBoolname(tterm, (int) i, bool_names);
660 assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
662 if (!version_filter(BOOLEAN, i))
664 else if (isObsolete(outform, name))
667 predval = pred(BOOLEAN, i);
668 if (predval != FAIL) {
669 _nc_STRCPY(buffer, name, sizeof(buffer));
671 _nc_STRCAT(buffer, "@", sizeof(buffer));
672 else if (i + 1 > num_bools)
678 if (column != indent && height > 1)
681 for_each_number(j, tterm) {
683 name = ExtNumname(tterm, (int) i, num_names);
684 assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
686 if (!version_filter(NUMBER, i))
688 else if (isObsolete(outform, name))
691 predval = pred(NUMBER, i);
692 if (predval != FAIL) {
693 if (tterm->Numbers[i] < 0) {
694 _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
697 _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
698 "%s#%d", name, tterm->Numbers[i]);
699 if (i + 1 > num_values)
706 if (column != indent && height > 1)
709 len += (int) (num_bools
711 + strlen(tterm->term_names) + 1);
717 if (outform == F_TERMCAP) {
718 if (termcap_reset != ABSENT_STRING) {
719 if (init_3string != ABSENT_STRING
720 && !strcmp(init_3string, termcap_reset))
721 DISCARD(init_3string);
723 if (reset_2string != ABSENT_STRING
724 && !strcmp(reset_2string, termcap_reset))
725 DISCARD(reset_2string);
729 for_each_string(j, tterm) {
731 name = ExtStrname(tterm, (int) i, str_names);
732 assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
734 capability = tterm->Strings[i];
736 if (!version_filter(STRING, i))
738 else if (isObsolete(outform, name))
743 * Extended names can be longer than 2 characters, but termcap programs
744 * cannot read those (filter them out).
746 if (outform == F_TERMCAP && (strlen(name) > 2))
750 if (outform == F_TERMCAP) {
752 * Some older versions of vi want rmir/smir to be defined
753 * for ich/ich1 to work. If they're not defined, force
754 * them to be output as defined and empty.
756 if (PRESENT(insert_character) || PRESENT(parm_ich)) {
757 if (SAME_CAP(i, enter_insert_mode)
758 && enter_insert_mode == ABSENT_STRING) {
759 _nc_STRCPY(buffer, "im=", sizeof(buffer));
764 if (SAME_CAP(i, exit_insert_mode)
765 && exit_insert_mode == ABSENT_STRING) {
766 _nc_STRCPY(buffer, "ei=", sizeof(buffer));
772 * termcap applications such as screen will be confused if sgr0
773 * is translated to a string containing rmacs. Filter that out.
775 if (PRESENT(exit_attribute_mode)) {
776 if (SAME_CAP(i, exit_attribute_mode)) {
778 char *my_sgr = set_attributes;
780 set_attributes = save_sgr;
782 trimmed_sgr0 = _nc_trim_sgr0(tterm);
783 if (strcmp(capability, trimmed_sgr0))
784 capability = trimmed_sgr0;
786 if (trimmed_sgr0 != exit_attribute_mode)
790 set_attributes = my_sgr;
795 predval = pred(STRING, i);
798 if (predval != FAIL) {
799 if (capability != ABSENT_STRING
800 && i + 1 > num_strings)
803 if (!VALID_STRING(capability)) {
804 _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
807 } else if (outform == F_TERMCAP || outform == F_TCONVERR) {
808 char *srccap = _nc_tic_expand(capability, TRUE, numbers);
809 int params = (((i < (int) SIZEOF(parametrized)) &&
814 : has_params(srccap)));
815 char *cv = _nc_infotocap(name, srccap, params);
818 if (outform == F_TCONVERR) {
819 _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
820 "%s=!!! %s WILL NOT CONVERT !!!",
822 } else if (suppress_untranslatable) {
825 char *s = srccap, *d = buffer;
826 _nc_SPRINTF(d, _nc_SLIMIT(sizeof(buffer)) "..%s=", name);
828 while ((*d = *s++) != 0) {
832 } else if (*d == '\\') {
839 _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
842 len += (int) strlen(capability) + 1;
845 char *src = _nc_tic_expand(capability,
846 outform == F_TERMINFO, numbers);
848 strcpy_DYN(&tmpbuf, 0);
849 strcpy_DYN(&tmpbuf, name);
850 strcpy_DYN(&tmpbuf, "=");
852 && (outform == F_TERMINFO
853 || outform == F_VARIABLE)) {
854 fmt_complex(tterm, name, src, 1);
856 strcpy_DYN(&tmpbuf, src);
858 len += (int) strlen(capability) + 1;
859 wrap_concat(tmpbuf.text);
863 /* e.g., trimmed_sgr0 */
864 if (capability != ABSENT_STRING &&
865 capability != CANCELLED_STRING &&
866 capability != tterm->Strings[i])
869 len += (int) (num_strings * 2);
872 * This piece of code should be an effective inverse of the functions
873 * postprocess_terminfo() and postprocess_terminfo() in parse_entry.c.
874 * Much more work should be done on this to support dumping termcaps.
876 if (tversion == V_HPUX) {
877 if (VALID_STRING(memory_lock)) {
878 _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
879 "meml=%s", memory_lock);
882 if (VALID_STRING(memory_unlock)) {
883 _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
884 "memu=%s", memory_unlock);
887 } else if (tversion == V_AIX) {
888 if (VALID_STRING(acs_chars)) {
890 const char *acstrans = "lqkxjmwuvtn";
892 char *tp, *sp, boxchars[11];
895 for (cp = acstrans; *cp; cp++) {
896 sp = (strchr) (acs_chars, *cp);
907 char *tmp = _nc_tic_expand(boxchars,
908 (outform == F_TERMINFO),
910 _nc_STRCPY(buffer, "box1=", sizeof(buffer));
911 while (*tmp != '\0') {
912 size_t have = strlen(buffer);
913 size_t next = strlen(tmp);
914 size_t want = have + next + 1;
919 * If the expanded string is too long for the buffer,
920 * chop it off and save the location where we chopped it.
922 if (want >= sizeof(buffer)) {
926 _nc_STRCAT(buffer, tmp, sizeof(buffer));
929 * If we chopped the buffer, replace the missing piece and
930 * shift everything to append the remainder.
935 while ((tmp[next] = tmp[last + next]) != '\0') {
948 * kludge: trim off trailer to avoid an extra blank line
949 * in infocmp -u output when there are no string differences
952 bool trimmed = FALSE;
953 j = (PredIdx) outbuf.used;
955 && outbuf.text[j - 1] == '\t'
956 && outbuf.text[j - 2] == '\n') {
960 && outbuf.text[j - 1] == ':'
961 && outbuf.text[j - 2] == '\t'
962 && outbuf.text[j - 3] == '\n'
963 && outbuf.text[j - 4] == '\\') {
968 outbuf.text[outbuf.used] = '\0';
970 strcpy_DYN(&outbuf, " ");
974 fprintf(stderr, "num_bools = %d\n", num_bools);
975 fprintf(stderr, "num_values = %d\n", num_values);
976 fprintf(stderr, "num_strings = %d\n", num_strings);
977 fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
978 tterm->term_names, len, outbuf.used, outbuf.text);
981 * Here's where we use infodump to trigger a more stringent length check
982 * for termcap-translation purposes.
983 * Return the length of the raw entry, without tc= expansions,
984 * It gives an idea of which entries are deadly to even *scan past*,
985 * as opposed to *use*.
987 return (infodump ? len : (int) termcap_length(outbuf.text));
991 kill_string(TERMTYPE *tterm, char *cap)
994 for (n = 0; n < NUM_STRINGS(tterm); ++n) {
995 if (cap == tterm->Strings[n]) {
996 tterm->Strings[n] = ABSENT_STRING;
1004 find_string(TERMTYPE *tterm, char *name)
1007 for (n = 0; n < NUM_STRINGS(tterm); ++n) {
1008 if (version_filter(STRING, n)
1009 && !strcmp(name, strnames[n])) {
1010 char *cap = tterm->Strings[n];
1011 if (VALID_STRING(cap)) {
1017 return ABSENT_STRING;
1021 * This is used to remove function-key labels from a termcap entry to
1025 kill_labels(TERMTYPE *tterm, int target)
1032 for (n = 0; n <= 10; ++n) {
1033 _nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "lf%d", n);
1034 if ((cap = find_string(tterm, name)) != ABSENT_STRING
1035 && kill_string(tterm, cap)) {
1036 target -= (int) (strlen(cap) + 5);
1046 * This is used to remove function-key definitions from a termcap entry to
1050 kill_fkeys(TERMTYPE *tterm, int target)
1057 for (n = 60; n >= 0; --n) {
1058 _nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "kf%d", n);
1059 if ((cap = find_string(tterm, name)) != ABSENT_STRING
1060 && kill_string(tterm, cap)) {
1061 target -= (int) (strlen(cap) + 5);
1071 * Check if the given acsc string is a 1-1 mapping, i.e., just-like-vt100.
1072 * Also, since this is for termcap, we only care about the line-drawing map.
1074 #define isLine(c) (strchr("lmkjtuvwqxn", c) != 0)
1077 one_one_mapping(const char *mapping)
1081 if (mapping != ABSENT_STRING) {
1083 while (mapping[n] != '\0') {
1084 if (isLine(mapping[n]) &&
1085 mapping[n] != mapping[n + 1]) {
1095 #define FMT_ENTRY() \
1096 fmt_entry(tterm, pred, \
1098 suppress_untranslatable, \
1101 #define SHOW_WHY PRINTF
1104 purged_acs(TERMTYPE *tterm)
1106 bool result = FALSE;
1108 if (VALID_STRING(acs_chars)) {
1109 if (!one_one_mapping(acs_chars)) {
1110 enter_alt_charset_mode = ABSENT_STRING;
1111 exit_alt_charset_mode = ABSENT_STRING;
1112 SHOW_WHY("# (rmacs/smacs removed for consistency)\n");
1120 encode_b64(char *target, char *source, unsigned state, int *saved)
1123 static const char data[] =
1124 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1125 "abcdefghijklmnopqrstuvwxyz"
1127 int ch = UChar(source[state]);
1129 switch (state % 3) {
1131 *target++ = data[ch & 077];
1132 *saved = (ch >> 6) & 3;
1135 *target++ = data[((ch << 2) | *saved) & 077];
1136 *saved = (ch >> 4) & 017;
1139 *target++ = data[((ch << 4) | *saved) & 077];
1140 *target++ = data[(ch >> 2) & 077];
1148 * Dump a single entry.
1151 dump_entry(TERMTYPE *tterm,
1152 int suppress_untranslatable,
1157 TERMTYPE save_tterm;
1165 unsigned offset = 0;
1169 if (_nc_write_object(tterm, bigbuf, &offset, sizeof(bigbuf)) == OK) {
1171 if (quickdump & 1) {
1174 wrap_concat("hex:");
1175 for (n = 0; n < offset; ++n) {
1176 sprintf(numbuf, "%02X", UChar(bigbuf[n]));
1177 wrap_concat(numbuf);
1180 if (quickdump & 2) {
1184 wrap_concat("b64:");
1185 for (n = 0; n < offset; ++n) {
1186 encode_b64(numbuf, bigbuf, n, &value);
1187 wrap_concat(numbuf);
1204 if (outform == F_TERMCAP || outform == F_TCONVERR) {
1205 critlen = MAX_TERMCAP_LENGTH;
1206 legend = "older termcap";
1208 set_obsolete_termcaps(tterm);
1210 critlen = MAX_TERMINFO_LENGTH;
1211 legend = "terminfo";
1215 save_sgr = set_attributes;
1217 if ((FMT_ENTRY() > critlen)
1220 save_tterm = *tterm;
1221 if (!suppress_untranslatable) {
1222 SHOW_WHY("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
1224 suppress_untranslatable = TRUE;
1226 if (FMT_ENTRY() > critlen) {
1228 * We pick on sgr because it's a nice long string capability that
1229 * is really just an optimization hack. Another good candidate is
1230 * acsc since it is both long and unused by BSD termcap.
1232 bool changed = FALSE;
1236 * Extended names are most likely function-key definitions. Drop
1240 for (n = STRCOUNT; n < NUM_STRINGS(tterm); n++) {
1241 const char *name = ExtStrname(tterm, (int) n, strnames);
1243 if (VALID_STRING(tterm->Strings[n])) {
1244 set_attributes = ABSENT_STRING;
1245 /* we remove long names anyway - only report the short */
1246 if (strlen(name) <= 2) {
1247 SHOW_WHY("# (%s removed to fit entry within %d bytes)\n",
1252 if (FMT_ENTRY() <= critlen)
1257 if (VALID_STRING(set_attributes)) {
1258 set_attributes = ABSENT_STRING;
1259 SHOW_WHY("# (sgr removed to fit entry within %d bytes)\n",
1263 if (!changed || (FMT_ENTRY() > critlen)) {
1264 if (purged_acs(tterm)) {
1265 acs_chars = ABSENT_STRING;
1266 SHOW_WHY("# (acsc removed to fit entry within %d bytes)\n",
1271 if (!changed || (FMT_ENTRY() > critlen)) {
1272 int oldversion = tversion;
1275 SHOW_WHY("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
1280 && kill_labels(tterm, len - critlen)) {
1281 SHOW_WHY("# (some labels capabilities suppressed to fit entry within %d bytes)\n",
1286 && kill_fkeys(tterm, len - critlen)) {
1287 SHOW_WHY("# (some function-key capabilities suppressed to fit entry within %d bytes)\n",
1291 if (len > critlen) {
1292 (void) fprintf(stderr,
1293 "warning: %s entry is %d bytes long\n",
1294 _nc_first_name(tterm->term_names),
1296 SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
1299 tversion = oldversion;
1301 set_attributes = save_sgr;
1302 *tterm = save_tterm;
1304 } else if (!version_filter(STRING, STR_IDX(acs_chars))) {
1305 save_tterm = *tterm;
1306 if (purged_acs(tterm)) {
1309 *tterm = save_tterm;
1314 dump_uses(const char *name, bool infodump)
1315 /* dump "use=" clauses in the appropriate format */
1317 char buffer[MAX_TERMINFO_LENGTH];
1319 if (outform == F_TERMCAP || outform == F_TCONVERR)
1321 _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
1322 "%s%s", infodump ? "use=" : "tc=", name);
1323 wrap_concat(buffer);
1330 * Trim any remaining whitespace.
1332 if (outbuf.used != 0) {
1333 bool infodump = (outform != F_TERMCAP && outform != F_TCONVERR);
1334 char delim = (char) (infodump ? ',' : ':');
1337 for (j = (int) outbuf.used - 1; j > 0; --j) {
1338 char ch = outbuf.text[j];
1341 } else if (isspace(UChar(ch))) {
1342 outbuf.used = (size_t) j;
1343 } else if (!infodump && ch == '\\') {
1344 outbuf.used = (size_t) j;
1345 } else if (ch == delim && (j == 0 || outbuf.text[j - 1] != '\\')) {
1346 outbuf.used = (size_t) (j + 1);
1351 outbuf.text[outbuf.used] = '\0';
1353 if (outbuf.text != 0) {
1354 (void) fputs(outbuf.text, stdout);
1357 return (int) outbuf.used;
1361 compare_entry(PredHook hook,
1362 TERMTYPE *tp GCC_UNUSED,
1364 /* compare two entries */
1367 NCURSES_CONST char *name;
1370 fputs(" comparing booleans.\n", stdout);
1371 for_each_boolean(j, tp) {
1372 i = BoolIndirect(j);
1373 name = ExtBoolname(tp, (int) i, bool_names);
1375 if (isObsolete(outform, name))
1378 (*hook) (CMP_BOOLEAN, i, name);
1382 fputs(" comparing numbers.\n", stdout);
1383 for_each_number(j, tp) {
1385 name = ExtNumname(tp, (int) i, num_names);
1387 if (isObsolete(outform, name))
1390 (*hook) (CMP_NUMBER, i, name);
1394 fputs(" comparing strings.\n", stdout);
1395 for_each_string(j, tp) {
1397 name = ExtStrname(tp, (int) i, str_names);
1399 if (isObsolete(outform, name))
1402 (*hook) (CMP_STRING, i, name);
1405 /* (void) fputs(" comparing use entries.\n", stdout); */
1406 (*hook) (CMP_USE, 0, "use");
1410 #define NOTSET(s) ((s) == 0)
1413 * This bit of legerdemain turns all the terminfo variable names into
1414 * references to locations in the arrays Booleans, Numbers, and Strings ---
1415 * precisely what's needed.
1421 set_obsolete_termcaps(TERMTYPE *tp)
1423 #include "capdefaults.c"
1427 * Convert an alternate-character-set string to canonical form: sorted and
1431 repair_acsc(TERMTYPE *tp)
1433 if (VALID_STRING(acs_chars)) {
1439 bool fix_needed = FALSE;
1441 for (n = 0, source = 0; acs_chars[n] != 0; n++) {
1442 target = UChar(acs_chars[n]);
1443 if (source >= target) {
1448 if (acs_chars[n + 1])
1452 memset(mapped, 0, sizeof(mapped));
1453 for (n = 0; acs_chars[n] != 0; n++) {
1454 source = UChar(acs_chars[n]);
1455 if ((target = (unsigned char) acs_chars[n + 1]) != 0) {
1456 mapped[source] = (char) target;
1459 extra = (char) source;
1462 for (n = m = 0; n < sizeof(mapped); n++) {
1464 acs_chars[m++] = (char) n;
1465 acs_chars[m++] = mapped[n];
1469 acs_chars[m++] = extra; /* garbage in, garbage out */