1 /****************************************************************************
2 * Copyright (c) 1998,1999 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 ****************************************************************************/
34 #define __INTERNAL_CAPS_VISIBLE
35 #include <progs.priv.h>
37 #include "dump_entry.h"
38 #include "termsort.c" /* this C file is generated */
39 #include <parametrized.h> /* so is this */
41 MODULE_ID("$Id: dump_entry.c,v 1.37 1999/03/14 12:29:30 tom Exp $")
45 #define DISCARD(string) string = ABSENT_STRING
47 static int tversion; /* terminfo version */
48 static int outform; /* output format to use */
49 static int sortmode; /* sort mode to use */
50 static int width = 60; /* max line width for listings */
51 static int column; /* current column, limited by 'width' */
52 static int oldcol; /* last value of column before wrap */
53 static int tracelevel; /* level of debug output */
54 static bool pretty; /* true if we format if-then-else strings */
56 static char *outbuf; /* the output-buffer */
57 static size_t out_used; /* ...its current length */
58 static size_t out_size; /* ...and its allocated length */
60 /* indirection pointers for implementing sort and display modes */
61 static const int *bool_indirect, *num_indirect, *str_indirect;
62 static NCURSES_CONST char * const *bool_names;
63 static NCURSES_CONST char * const *num_names;
64 static NCURSES_CONST char * const *str_names;
66 static const char *separator, *trailer;
68 /* cover various ports and variants of terminfo */
69 #define V_ALLCAPS 0 /* all capabilities (SVr4, XSI, ncurses) */
70 #define V_SVR1 1 /* SVR1, Ultrix */
71 #define V_HPUX 2 /* HP/UX */
72 #define V_AIX 3 /* AIX */
73 #define V_BSD 4 /* BSD */
75 #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
78 #define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
79 #define NumIndirect(j) ((j >= NUMCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
80 #define StrIndirect(j) ((j >= STRCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
82 #define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
83 #define NumIndirect(j) ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
84 #define StrIndirect(j) ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
88 void _nc_leaks_dump_entry(void)
97 NCURSES_CONST char *nametrans(const char *name)
98 /* translate a capability name from termcap to terminfo */
100 const struct name_table_entry *np;
102 if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0)
106 if (bool_from_termcap[np->nte_index])
107 return(boolcodes[np->nte_index]);
111 if (num_from_termcap[np->nte_index])
112 return(numcodes[np->nte_index]);
116 if (str_from_termcap[np->nte_index])
117 return(strcodes[np->nte_index]);
124 void dump_init(const char *version, int mode, int sort, int twidth, int traceval, bool formatted)
125 /* set up for entry display */
129 tracelevel = traceval;
133 tversion = V_ALLCAPS;
134 else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
135 || !strcmp(version, "Ultrix"))
137 else if (!strcmp(version, "HP"))
139 else if (!strcmp(version, "AIX"))
141 else if (!strcmp(version, "BSD"))
144 tversion = V_ALLCAPS;
146 /* implement display modes */
147 switch (outform = mode)
151 bool_names = boolnames;
152 num_names = numnames;
153 str_names = strnames;
154 separator = twidth ? ", " : ",";
159 bool_names = boolfnames;
160 num_names = numfnames;
161 str_names = strfnames;
162 separator = twidth ? ", " : ",";
168 bool_names = boolcodes;
169 num_names = numcodes;
170 str_names = strcodes;
176 /* implement sort modes */
177 switch(sortmode = sort)
181 (void) fprintf(stderr,
182 "%s: sorting by term structure order\n", _nc_progname);
187 (void) fprintf(stderr,
188 "%s: sorting by terminfo name order\n", _nc_progname);
189 bool_indirect = bool_terminfo_sort;
190 num_indirect = num_terminfo_sort;
191 str_indirect = str_terminfo_sort;
196 (void) fprintf(stderr,
197 "%s: sorting by C variable order\n", _nc_progname);
198 bool_indirect = bool_variable_sort;
199 num_indirect = num_variable_sort;
200 str_indirect = str_variable_sort;
205 (void) fprintf(stderr,
206 "%s: sorting by termcap name order\n", _nc_progname);
207 bool_indirect = bool_termcap_sort;
208 num_indirect = num_termcap_sort;
209 str_indirect = str_termcap_sort;
214 (void) fprintf(stderr,
215 "%s: width = %d, tversion = %d, outform = %d\n",
216 _nc_progname, width, tversion, outform);
219 static TERMTYPE *cur_type;
221 static int dump_predicate(int type, int idx)
222 /* predicate function to use for ordinary decompilation */
226 return (cur_type->Booleans[idx] == FALSE)
227 ? FAIL : cur_type->Booleans[idx];
230 return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
231 ? FAIL : cur_type->Numbers[idx];
234 return (cur_type->Strings[idx] != ABSENT_STRING)
238 return(FALSE); /* pacify compiler */
241 static void set_obsolete_termcaps(TERMTYPE *tp);
242 static void repair_acsc(TERMTYPE *tp);
244 /* is this the index of a function key string? */
245 #define FNKEY(i) (((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268))
247 static bool version_filter(int type, int idx)
248 /* filter out capabilities we may want to suppress */
252 case V_ALLCAPS: /* SVr4, XSI Curses */
255 case V_SVR1: /* System V Release 1, Ultrix */
259 /* below and including xon_xoff */
260 return ((idx <= 20) ? TRUE : FALSE);
262 /* below and including width_status_line */
263 return ((idx <= 7) ? TRUE : FALSE);
265 /* below and including prtr_non */
266 return ((idx <= 144) ? TRUE : FALSE);
270 case V_HPUX: /* Hewlett-Packard */
274 /* below and including xon_xoff */
275 return ((idx <= 20) ? TRUE : FALSE);
277 /* below and including label_width */
278 return ((idx <= 10) ? TRUE : FALSE);
280 if (idx <= 144) /* below and including prtr_non */
282 else if (FNKEY(idx)) /* function keys */
284 else if (idx==147||idx==156||idx==157) /* plab_norm,label_on,label_off */
291 case V_AIX: /* AIX */
295 /* below and including xon_xoff */
296 return ((idx <= 20) ? TRUE : FALSE);
298 /* below and including width_status_line */
299 return ((idx <= 7) ? TRUE : FALSE);
301 if (idx <= 144) /* below and including prtr_non */
303 else if (FNKEY(idx)) /* function keys */
310 case V_BSD: /* BSD */
314 return bool_from_termcap[idx];
316 return num_from_termcap[idx];
318 return str_from_termcap[idx];
323 return(FALSE); /* pacify the compiler */
327 void append_output (const char *src)
333 size_t need = strlen(src);
334 size_t want = need + out_used + 1;
335 if (want > out_size) {
336 out_size += want; /* be generous */
338 outbuf = malloc(out_size);
340 outbuf = realloc(outbuf, out_size);
342 (void)strcpy(outbuf + out_used, src);
348 void force_wrap(void)
351 append_output(trailer);
356 void wrap_concat(const char *src)
358 int need = strlen(src);
359 int want = strlen(separator) + need;
362 && column + want > width) {
366 append_output(separator);
370 #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
371 if ((size_t)(last - first) > sizeof(sep_trail)-1 \
372 && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
373 first += sizeof(sep_trail)-2
375 /* Returns the nominal length of the buffer assuming it is termcap format,
376 * i.e., the continuation sequence is treated as a single character ":".
378 * There are several implementations of termcap which read the text into a
379 * fixed-size buffer. Generally they strip the newlines from the text, but may
380 * not do it until after the buffer is read. Also, "tc=" resolution may be
381 * expanded in the same buffer. This function is useful for measuring the size
382 * of the best fixed-buffer implementation; the worst case may be much worse.
384 #ifdef TEST_TERMCAP_LENGTH
385 static int termcap_length(const char *src)
387 static const char pattern[] = ":\\\n\t:";
390 const char *const t = src + strlen(src);
392 while (*src != '\0') {
393 IGNORE_SEP_TRAIL(src, t, pattern);
400 #define termcap_length(src) strlen(src)
403 static char * fmt_complex(char *dst, char *src, int level)
409 while (*src != '\0') {
419 case 't': /* "then" */
420 case 'e': /* "else" */
424 for (n = 0; n <= level; n++)
430 src = fmt_complex(dst, src, level+1);
432 } else if (level == 1) {
433 _nc_warning("%%%c without %%?", *src);
438 case ';': /* "endif" */
443 for (n = 0; n < level; n++)
450 _nc_warning("%%; without %%?");
463 int fmt_entry(TERMTYPE *tterm,
464 int (*pred)(int type, int idx),
465 bool suppress_untranslatable,
470 char buffer[MAX_TERMINFO_LENGTH];
471 NCURSES_CONST char *name;
478 #define WRAP_CONCAT \
479 wrap_concat(buffer); \
482 len = 12; /* terminfo file-header */
486 pred = dump_predicate;
490 append_output(tterm->term_names);
491 append_output(separator);
495 for_each_boolean(j,tterm) {
497 name = ExtBoolname(tterm,i,bool_names);
499 if (!version_filter(BOOLEAN, i))
501 else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
502 && (OBSOLETE(name) && outform != F_LITERAL))
505 predval = pred(BOOLEAN, i);
506 if (predval != FAIL) {
507 (void) strcpy(buffer, name);
509 (void) strcat(buffer, "@");
510 else if (i + 1 > num_bools)
516 if (column != INDENT)
519 for_each_number(j,tterm) {
521 name = ExtNumname(tterm,i,num_names);
523 if (!version_filter(NUMBER, i))
525 else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
526 && (OBSOLETE(name) && outform != F_LITERAL))
529 predval = pred(NUMBER, i);
530 if (predval != FAIL) {
531 if (tterm->Numbers[i] < 0) {
532 sprintf(buffer, "%s@", name);
534 sprintf(buffer, "%s#%d", name, tterm->Numbers[i]);
535 if (i + 1 > num_values)
542 if (column != INDENT)
547 + strlen(tterm->term_names) + 1;
552 for_each_string(j, tterm) {
554 name = ExtStrname(tterm,i,str_names);
556 if (!version_filter(STRING, i))
558 else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
559 && (OBSOLETE(name) && outform != F_LITERAL))
563 * Some older versions of vi want rmir/smir to be defined
564 * for ich/ich1 to work. If they're not defined, force
565 * them to be output as defined and empty.
567 if (outform==F_TERMCAP)
571 if (insert_character || parm_ich)
573 if (&tterm->Strings[i] == &enter_insert_mode
574 && enter_insert_mode == ABSENT_STRING)
576 (void) strcpy(buffer, "im=");
580 if (&tterm->Strings[i] == &exit_insert_mode
581 && exit_insert_mode == ABSENT_STRING)
583 (void) strcpy(buffer, "ei=");
588 if (init_3string != 0
589 && termcap_reset != 0
590 && !strcmp(init_3string, termcap_reset))
591 DISCARD(init_3string);
593 if (reset_2string != 0
594 && termcap_reset != 0
595 && !strcmp(reset_2string, termcap_reset))
596 DISCARD(reset_2string);
599 predval = pred(STRING, i);
601 if (predval != FAIL) {
602 if (tterm->Strings[i] != ABSENT_STRING
603 && i + 1 > num_strings)
605 if (!VALID_STRING(tterm->Strings[i]))
606 sprintf(buffer, "%s@", name);
607 else if (outform == F_TERMCAP || outform == F_TCONVERR)
609 char *srccap = _nc_tic_expand(tterm->Strings[i], FALSE, numbers);
610 char *cv = _nc_infotocap(name, srccap, parametrized[i]);
614 if (outform == F_TCONVERR)
615 sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!", name, srccap);
616 else if (suppress_untranslatable)
619 sprintf(buffer, "..%s=%s", name, srccap);
622 sprintf(buffer, "%s=%s", name, cv);
623 len += strlen(tterm->Strings[i]) + 1;
627 char *src = _nc_tic_expand(tterm->Strings[i], outform==F_TERMINFO, numbers);
628 sprintf(buffer, "%s=", name);
629 if (pretty && outform==F_TERMINFO)
630 fmt_complex(buffer + strlen(buffer), src, 1);
633 len += strlen(tterm->Strings[i]) + 1;
640 len += num_strings * 2;
643 * This piece of code should be an effective inverse of the functions
644 * postprocess_terminfo and postprocess_terminfo in parse_entry.c.
645 * Much more work should be done on this to support dumping termcaps.
647 if (tversion == V_HPUX)
651 (void) sprintf(buffer, "meml=%s", memory_lock);
656 (void) sprintf(buffer, "memu=%s", memory_unlock);
660 else if (tversion == V_AIX)
662 if (VALID_STRING(acs_chars))
665 const char *acstrans = "lqkxjmwuvtn";
667 char *tp, *sp, boxchars[11];
670 for (cp = acstrans; *cp; cp++)
672 sp = strchr(acs_chars, *cp);
685 (void) strcpy(buffer, "box1=");
686 (void) strcat(buffer, _nc_tic_expand(boxchars, outform==F_TERMINFO, numbers));
693 * kludge: trim off trailer to avoid an extra blank line
694 * in infocmp -u output when there are no string differences
700 && outbuf[j-1] == '\t'
701 && outbuf[j-2] == '\n') {
704 && outbuf[j-1] == ':'
705 && outbuf[j-2] == '\t'
706 && outbuf[j-3] == '\n'
707 && outbuf[j-4] == '\\') {
710 outbuf[out_used] = '\0';
715 fprintf(stderr, "num_bools = %d\n", num_bools);
716 fprintf(stderr, "num_values = %d\n", num_values);
717 fprintf(stderr, "num_strings = %d\n", num_strings);
718 fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
719 tterm->term_names, len, out_used, outbuf);
722 * Here's where we use infodump to trigger a more stringent length check
723 * for termcap-translation purposes.
724 * Return the length of the raw entry, without tc= expansions,
725 * It gives an idea of which entries are deadly to even *scan past*,
726 * as opposed to *use*.
728 return(infodump ? len : termcap_length(outbuf));
731 int dump_entry(TERMTYPE *tterm, bool limited, int numbers, int (*pred)(int type, int idx))
732 /* dump a single entry */
738 if (outform==F_TERMCAP || outform==F_TCONVERR)
740 critlen = MAX_TERMCAP_LENGTH;
741 legend = "older termcap";
743 set_obsolete_termcaps(tterm);
747 critlen = MAX_TERMINFO_LENGTH;
752 if (((len = fmt_entry(tterm, pred, FALSE, infodump, numbers)) > critlen) && limited)
754 (void) printf("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
756 if ((len = fmt_entry(tterm, pred, TRUE, infodump, numbers)) > critlen)
759 * We pick on sgr because it's a nice long string capability that
760 * is really just an optimization hack.
762 char *oldsgr = set_attributes;
763 set_attributes = ABSENT_STRING;
764 (void) printf("# (sgr removed to fit entry within %d bytes)\n",
766 if ((len = fmt_entry(tterm, pred, TRUE, infodump, numbers)) > critlen)
768 int oldversion = tversion;
771 (void) printf("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
774 if ((len = fmt_entry(tterm, pred, TRUE, infodump, numbers)) > critlen)
776 (void) fprintf(stderr,
777 "warning: %s entry is %d bytes long\n",
778 _nc_first_name(tterm->term_names),
781 "# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
784 tversion = oldversion;
786 set_attributes = oldsgr;
790 (void) fputs(outbuf, stdout);
794 int dump_uses(const char *name, bool infodump)
795 /* dump "use=" clauses in the appropriate format */
797 char buffer[MAX_TERMINFO_LENGTH];
800 (void)sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name);
802 (void) fputs(outbuf, stdout);
806 void compare_entry(void (*hook)(int t, int i, const char *name), TERMTYPE *tp GCC_UNUSED)
807 /* compare two entries */
810 NCURSES_CONST char * name;
812 (void) fputs(" comparing booleans.\n", stdout);
813 for_each_boolean(j,tp)
816 name = ExtBoolname(tp,i,bool_names);
818 if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
819 && (OBSOLETE(name) && outform != F_LITERAL))
822 (*hook)(BOOLEAN, i, name);
825 (void) fputs(" comparing numbers.\n", stdout);
826 for_each_number(j,tp)
829 name = ExtNumname(tp,i,num_names);
831 if ((outform==F_LITERAL || outform==F_TERMINFO || outform==F_VARIABLE)
832 && (OBSOLETE(name) && outform != F_LITERAL))
835 (*hook)(NUMBER, i, name);
838 (void) fputs(" comparing strings.\n", stdout);
839 for_each_string(j,tp)
842 name = ExtStrname(tp,i,str_names);
844 if ((outform==F_LITERAL || outform==F_TERMINFO || outform==F_VARIABLE)
845 && (OBSOLETE(name) && outform != F_LITERAL))
848 (*hook)(STRING, i, name);
852 #define NOTSET(s) ((s) == 0)
855 * This bit of legerdemain turns all the terminfo variable names into
856 * references to locations in the arrays Booleans, Numbers, and Strings ---
857 * precisely what's needed.
862 static void set_obsolete_termcaps(TERMTYPE *tp)
864 #include "capdefaults.c"
868 * Convert an alternate-character-set string to canonical form: sorted and
871 static void repair_acsc(TERMTYPE *tp)
873 if (VALID_STRING(acs_chars)) {
879 bool fix_needed = FALSE;
881 for (n = 0, source = 0; acs_chars[n] != 0; n++) {
882 target = acs_chars[n];
883 if (source >= target) {
892 memset(mapped, 0, sizeof(mapped));
893 for (n = 0; acs_chars[n] != 0; n++) {
894 source = acs_chars[n];
895 if ((target = (unsigned char)acs_chars[n+1]) != 0) {
896 mapped[source] = target;
902 for (n = m = 0; n < sizeof(mapped); n++) {
905 acs_chars[m++] = mapped[n];
909 acs_chars[m++] = extra; /* garbage in, garbage out */