2 /***************************************************************************
4 ****************************************************************************
5 * ncurses is copyright (C) 1992-1995 *
7 * zmbenhal@netcom.com *
9 * esr@snark.thyrsus.com *
11 * Permission is hereby granted to reproduce and distribute ncurses *
12 * by any means and for any fee, whether alone or as part of a *
13 * larger distribution, in source or in binary form, PROVIDED *
14 * this notice is included with any such distribution, and is not *
15 * removed from any of its header files. Mention of ncurses in any *
16 * applications linked with it is highly appreciated. *
18 * ncurses comes AS IS with no warranty, implied or expressed. *
20 ***************************************************************************/
22 #define __INTERNAL_CAPS_VISIBLE
23 #include <progs.priv.h>
26 #include "dump_entry.h"
27 #include "termsort.c" /* this C file is generated */
28 #include "parametrized.h" /* so is this */
30 MODULE_ID("$Id: dump_entry.c,v 1.17 1997/05/10 17:35:30 tom Exp $")
34 static int tversion; /* terminfo version */
35 static int outform; /* output format to use */
36 static int sortmode; /* sort mode to use */
37 static int width = 60; /* max line width for listings */
38 static int column; /* current column, limited by 'width' */
39 static int oldcol; /* last value of column before wrap */
40 static int tracelevel; /* level of debug output */
42 static char *outbuf; /* the output-buffer */
43 static size_t out_used; /* ...its current length */
44 static size_t out_size; /* ...and its allocated length */
46 /* indirection pointers for implementing sort and display modes */
47 static const int *bool_indirect, *num_indirect, *str_indirect;
48 static char * const *bool_names, * const *num_names, * const *str_names;
50 static const char *separator, *trailer;
52 /* cover various ports and variants of terminfo */
53 #define V_ALLCAPS 0 /* all capabilities (SVr4, XSI, ncurses) */
54 #define V_SVR1 1 /* SVR1, Ultrix */
55 #define V_HPUX 2 /* HP/UX */
56 #define V_AIX 3 /* AIX */
57 #define V_BSD 4 /* BSD */
59 #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
62 void _nc_leaks_dump_entry(void)
71 char *nametrans(const char *name)
72 /* translate a capability name from termcap to terminfo */
74 const struct name_table_entry *np;
76 if ((np = _nc_find_entry(name, _nc_info_hash_table)) != NULL)
80 if (bool_from_termcap[np->nte_index])
81 return(boolcodes[np->nte_index]);
85 if (num_from_termcap[np->nte_index])
86 return(numcodes[np->nte_index]);
90 if (str_from_termcap[np->nte_index])
91 return(strcodes[np->nte_index]);
98 void dump_init(const char *version, int mode, int sort, int twidth, int traceval)
99 /* set up for entry display */
102 tracelevel = traceval;
105 if (version == (char *)NULL)
106 tversion = V_ALLCAPS;
107 else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
108 || !strcmp(version, "Ultrix"))
110 else if (!strcmp(version, "HP"))
112 else if (!strcmp(version, "AIX"))
114 else if (!strcmp(version, "BSD"))
117 tversion = V_ALLCAPS;
119 /* implement display modes */
120 switch (outform = mode)
124 bool_names = boolnames;
125 num_names = numnames;
126 str_names = strnames;
127 separator = twidth ? ", " : ",";
132 bool_names = boolfnames;
133 num_names = numfnames;
134 str_names = strfnames;
135 separator = twidth ? ", " : ",";
141 bool_names = boolcodes;
142 num_names = numcodes;
143 str_names = strcodes;
149 /* implement sort modes */
150 switch(sortmode = sort)
154 (void) fprintf(stderr,
155 "%s: sorting by term structure order\n", _nc_progname);
160 (void) fprintf(stderr,
161 "%s: sorting by terminfo name order\n", _nc_progname);
162 bool_indirect = bool_terminfo_sort;
163 num_indirect = num_terminfo_sort;
164 str_indirect = str_terminfo_sort;
169 (void) fprintf(stderr,
170 "%s: sorting by C variable order\n", _nc_progname);
171 bool_indirect = bool_variable_sort;
172 num_indirect = num_variable_sort;
173 str_indirect = str_variable_sort;
178 (void) fprintf(stderr,
179 "%s: sorting by termcap name order\n", _nc_progname);
180 bool_indirect = bool_termcap_sort;
181 num_indirect = num_termcap_sort;
182 str_indirect = str_termcap_sort;
187 (void) fprintf(stderr,
188 "%s: width = %d, tversion = %d, outform = %d\n",
189 _nc_progname, width, tversion, outform);
192 static int trailing_spaces(const char *src)
199 /* this deals with differences over whether 0x7f and 0x80..0x9f are controls */
200 #define CHAR_OF(s) (*(unsigned const char *)(s))
201 #define REALCTL(s) (CHAR_OF(s) < 127 && iscntrl(CHAR_OF(s)))
202 #define REALPRINT(s) (CHAR_OF(s) < 127 && isprint(CHAR_OF(s)))
204 char *expand(char *srcp)
206 static char buffer[1024];
208 const char *ptr, *str = (srcp == ABSENT_STRING
209 || srcp == CANCELLED_STRING) ? "" : srcp;
210 bool islong = (strlen(str) > 3);
215 if (*str == '%' && REALPRINT(str+1)) {
216 buffer[bufp++] = *str++;
217 buffer[bufp++] = *str;
219 else if (*str == '\033') {
220 buffer[bufp++] = '\\';
221 buffer[bufp++] = 'E';
223 else if (*str == '\\' && (outform==F_TERMINFO) && (str == srcp || str[-1] != '^')) {
224 buffer[bufp++] = '\\';
225 buffer[bufp++] = '\\';
227 else if (*str == ' ' && (outform==F_TERMINFO) && (str == srcp || trailing_spaces(str))) {
228 buffer[bufp++] = '\\';
229 buffer[bufp++] = 's';
231 else if ((*str == ',' || *str == ':' || *str == '^') && (outform==F_TERMINFO)) {
232 buffer[bufp++] = '\\';
233 buffer[bufp++] = *str;
235 else if (REALPRINT(str) && (*str != ',' && *str != ':' && !(*str == '!' && outform!=F_TERMINFO) && *str != '^'))
236 buffer[bufp++] = *str;
237 #if 0 /* FIXME: this would be more readable */
238 else if (*str == '\b') {
239 buffer[bufp++] = '\\';
240 buffer[bufp++] = 'b';
242 else if (*str == '\f') {
243 buffer[bufp++] = '\\';
244 buffer[bufp++] = 'f';
246 else if (*str == '\t' && islong) {
247 buffer[bufp++] = '\\';
248 buffer[bufp++] = 't';
251 else if (*str == '\r' && (islong || (strlen(srcp) > 2 && str[1] == '\0'))) {
252 buffer[bufp++] = '\\';
253 buffer[bufp++] = 'r';
255 else if (*str == '\n' && islong) {
256 buffer[bufp++] = '\\';
257 buffer[bufp++] = 'n';
259 #define UnCtl(c) ((0xff & (c)) + '@')
260 else if (REALCTL(str) && *str != '\\' && (!islong || isdigit(str[1])))
262 (void) sprintf(&buffer[bufp], "^%c", UnCtl(*str));
267 (void) sprintf(&buffer[bufp], "\\%03o", 0xff & *str);
278 static TERMTYPE *cur_type;
280 static int dump_predicate(int type, int idx)
281 /* predicate function to use for ordinary decompilation */
285 return (cur_type->Booleans[idx] == FALSE)
286 ? FAIL : cur_type->Booleans[idx];
289 return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
290 ? FAIL : cur_type->Numbers[idx];
293 return (cur_type->Strings[idx] != ABSENT_STRING)
297 return(FALSE); /* pacify compiler */
300 static void set_obsolete_termcaps(TERMTYPE *tp);
302 /* is this the index of a function key string? */
303 #define FNKEY(i) (((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268))
305 static bool version_filter(int type, int idx)
306 /* filter out capabilities we may want to suppress */
310 case V_ALLCAPS: /* SVr4, XSI Curses */
313 case V_SVR1: /* System V Release 1, Ultrix */
317 return (idx <= 20); /* below and including xon_xoff */
319 return (idx <= 7); /* below and including width_status_line */
321 return (idx <= 144); /* below and including prtr_non */
325 case V_HPUX: /* Hewlett-Packard */
329 return (idx <= 20); /* below and including xon_xoff */
331 return (idx <= 10); /* below and including label_width */
333 if (idx <= 144) /* below and including prtr_non */
335 else if (FNKEY(idx)) /* function keys */
337 else if (idx==147||idx==156||idx==157) /* plab_norm,label_on,label_off */
344 case V_AIX: /* AIX */
348 return (idx <= 20); /* below and including xon_xoff */
350 return (idx <= 7); /* below and including width_status_line */
352 if (idx <= 144) /* below and including prtr_non */
354 else if (FNKEY(idx)) /* function keys */
361 case V_BSD: /* BSD */
365 return bool_from_termcap[idx];
367 return num_from_termcap[idx];
369 return str_from_termcap[idx];
374 return(FALSE); /* pacify the compiler */
378 void append_output (const char *src)
384 size_t need = strlen(src);
385 size_t want = need + out_used + 1;
386 if (want > out_size) {
387 out_size += want; /* be generous */
389 outbuf = malloc(out_size);
391 outbuf = realloc(outbuf, out_size);
393 (void)strcpy(outbuf + out_used, src);
399 void force_wrap(void)
402 append_output(trailer);
407 void wrap_concat(const char *src)
409 int need = strlen(src);
410 int want = strlen(separator) + need;
413 && column + want > width) {
417 append_output(separator);
421 #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
422 if ((size_t)(last - first) > sizeof(sep_trail)-1 \
423 && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
424 first += sizeof(sep_trail)-2
426 /* Returns the nominal length of the buffer assuming it is termcap format,
427 * i.e., the continuation sequence is treated as a single character ":".
429 * There are several implementations of termcap which read the text into a
430 * fixed-size buffer. Generally they strip the newlines from the text, but may
431 * not do it until after the buffer is read. Also, "tc=" resolution may be
432 * expanded in the same buffer. This function is useful for measuring the size
433 * of the best fixed-buffer implementation; the worst case may be much worse.
435 #ifdef TEST_TERMCAP_LENGTH
436 static int termcap_length(const char *src)
438 static const char pattern[] = ":\\\n\t:";
441 const char *const t = src + strlen(src);
443 while (*src != '\0') {
444 IGNORE_SEP_TRAIL(src, t, pattern);
451 #define termcap_length(src) strlen(src)
454 int fmt_entry(TERMTYPE *tterm,
455 int (*pred)(int type, int idx),
456 bool suppress_untranslatable,
460 char buffer[MAX_TERMINFO_LENGTH];
467 #define WRAP_CONCAT \
468 wrap_concat(buffer); \
471 len = 12; /* terminfo file-header */
475 pred = dump_predicate;
479 append_output(tterm->term_names);
480 append_output(separator);
484 for (j=0; j < BOOLCOUNT; j++) {
485 if (sortmode == S_NOSORT)
488 i = bool_indirect[j];
490 if (!version_filter(BOOLEAN, i))
492 else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
493 && (OBSOLETE(bool_names[i]) && outform != F_LITERAL))
496 predval = pred(BOOLEAN, i);
497 if (predval != FAIL) {
498 (void) strcpy(buffer, bool_names[i]);
500 (void) strcat(buffer, "@");
501 else if (i + 1 > num_bools)
507 if (column != INDENT)
510 for (j=0; j < NUMCOUNT; j++) {
511 if (sortmode == S_NOSORT)
516 if (!version_filter(NUMBER, i))
518 else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
519 && (OBSOLETE(num_names[i]) && outform != F_LITERAL))
522 predval = pred(NUMBER, i);
523 if (predval != FAIL) {
524 if (tterm->Numbers[i] < 0) {
525 sprintf(buffer, "%s@", num_names[i]);
527 sprintf(buffer, "%s#%d", num_names[i], tterm->Numbers[i]);
528 if (i + 1 > num_values)
535 if (column != INDENT)
540 + strlen(tterm->term_names) + 1;
544 for (j=0; j < STRCOUNT; j++) {
545 if (sortmode == S_NOSORT)
550 if (!version_filter(STRING, i))
552 else if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
553 && (OBSOLETE(str_names[i]) && outform != F_LITERAL))
557 * Some older versions of vi want rmir/smir to be defined
558 * for ich/ich1 to work. If they're not defined, force
559 * them to be output as defined and empty.
561 if (outform==F_TERMCAP)
564 if (insert_character || parm_ich)
566 if (&tterm->Strings[i] == &enter_insert_mode
567 && enter_insert_mode == ABSENT_STRING)
569 (void) strcpy(buffer, "im=");
573 if (&tterm->Strings[i] == &exit_insert_mode
574 && exit_insert_mode == ABSENT_STRING)
576 (void) strcpy(buffer, "ei=");
581 predval = pred(STRING, i);
583 if (predval != FAIL) {
584 if (tterm->Strings[i] != ABSENT_STRING
585 && i + 1 > num_strings)
587 if (tterm->Strings[i] == ABSENT_STRING
588 || tterm->Strings[i] == CANCELLED_STRING)
589 sprintf(buffer, "%s@", str_names[i]);
590 else if (outform == F_TERMCAP || outform == F_TCONVERR)
592 char *srccap = expand(tterm->Strings[i]);
593 char *cv = _nc_infotocap(str_names[i], srccap,parametrized[i]);
595 if (cv == (char *)NULL)
597 if (outform == F_TCONVERR)
598 sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!", str_names[i], srccap);
599 else if (suppress_untranslatable)
602 sprintf(buffer, "..%s=%s", str_names[i], srccap);
605 sprintf(buffer, "%s=%s", str_names[i], cv);
606 len += strlen(tterm->Strings[i]) + 1;
610 sprintf(buffer,"%s=%s",str_names[i],expand(tterm->Strings[i]));
611 len += strlen(tterm->Strings[i]) + 1;
618 len += num_strings * 2;
621 * This piece of code should be an effective inverse of the functions
622 * postprocess_terminfo and postprocess_terminfo in parse_entry.c.
623 * Much more work should be done on this to support dumping termcaps.
625 if (tversion == V_HPUX)
629 (void) sprintf(buffer, "meml=%s", memory_lock);
634 (void) sprintf(buffer, "memu=%s", memory_unlock);
638 else if (tversion == V_AIX)
643 const char *acstrans = "lqkxjmwuvtn";
645 char *tp, *sp, boxchars[11];
648 for (cp = acstrans; *cp; cp++)
650 sp = strchr(acs_chars, *cp);
663 (void) strcpy(buffer, "box1=");
664 (void) strcat(buffer, expand(boxchars));
671 * kludge: trim off trailer to avoid an extra blank line
672 * in infocmp -u output when there are no string differences
678 && outbuf[j-1] == '\t'
679 && outbuf[j-2] == '\n') {
682 && outbuf[j-1] == ':'
683 && outbuf[j-2] == '\t'
684 && outbuf[j-3] == '\n'
685 && outbuf[j-4] == '\\') {
688 outbuf[out_used] = '\0';
693 fprintf(stderr, "num_bools = %d\n", num_bools);
694 fprintf(stderr, "num_values = %d\n", num_values);
695 fprintf(stderr, "num_strings = %d\n", num_strings);
696 fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
697 tterm->term_names, len, out_used, outbuf);
700 * Here's where we use infodump to trigger a more stringent length check
701 * for termcap-translation purposes.
702 * Return the length of the raw entry, without tc= expansions,
703 * It gives an idea of which entries are deadly to even *scan past*,
704 * as opposed to *use*.
706 return(infodump ? len : termcap_length(outbuf));
709 int dump_entry(TERMTYPE *tterm, bool limited, int (*pred)(int type, int idx))
710 /* dump a single entry */
716 if (outform==F_TERMCAP || outform==F_TCONVERR)
718 critlen = MAX_TERMCAP_LENGTH;
719 legend = "older termcap";
721 set_obsolete_termcaps(tterm);
725 critlen = MAX_TERMINFO_LENGTH;
730 if (((len = fmt_entry(tterm, pred, FALSE, infodump)) > critlen) && limited)
732 (void) printf("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
734 if ((len = fmt_entry(tterm, pred, TRUE, infodump)) > critlen)
737 * We pick on sgr because it's a nice long string capability that
738 * is really just an optimization hack.
740 char *oldsgr = set_attributes;
741 set_attributes = ABSENT_STRING;
742 (void) printf("# (sgr removed to fit entry within %d bytes)\n",
744 if ((len = fmt_entry(tterm, pred, TRUE, infodump)) > critlen)
746 int oldversion = tversion;
749 (void) printf("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
752 if ((len = fmt_entry(tterm, pred, TRUE, infodump)) > critlen)
754 (void) fprintf(stderr,
755 "warning: %s entry is %d bytes long\n",
756 _nc_first_name(tterm->term_names),
759 "# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
762 tversion = oldversion;
764 set_attributes = oldsgr;
768 (void) fputs(outbuf, stdout);
772 int dump_uses(const char *name, bool infodump)
773 /* dump "use=" clauses in the appropriate format */
775 char buffer[MAX_TERMINFO_LENGTH];
778 (void)sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name);
780 (void) fputs(outbuf, stdout);
784 void compare_entry(void (*hook)(int t, int i, const char *name))
785 /* compare two entries */
789 (void) fputs(" comparing booleans.\n", stdout);
790 for (j=0; j < BOOLCOUNT; j++)
792 if (sortmode == S_NOSORT)
795 i = bool_indirect[j];
797 if ((outform == F_LITERAL || outform == F_TERMINFO || outform == F_VARIABLE)
798 && (OBSOLETE(bool_names[i]) && outform != F_LITERAL))
801 (*hook)(BOOLEAN, i, bool_names[i]);
804 (void) fputs(" comparing numbers.\n", stdout);
805 for (j=0; j < NUMCOUNT; j++)
807 if (sortmode == S_NOSORT)
812 if ((outform==F_LITERAL || outform==F_TERMINFO || outform==F_VARIABLE)
813 && (OBSOLETE(num_names[i]) && outform != F_LITERAL))
816 (*hook)(NUMBER, i, num_names[i]);
819 (void) fputs(" comparing strings.\n", stdout);
820 for (j=0; j < STRCOUNT; j++)
822 if (sortmode == S_NOSORT)
827 if ((outform==F_LITERAL || outform==F_TERMINFO || outform==F_VARIABLE)
828 && (OBSOLETE(str_names[i]) && outform != F_LITERAL))
831 (*hook)(STRING, i, str_names[i]);
835 #define NOTSET(s) ((s) == (char *)NULL)
838 * This bit of legerdemain turns all the terminfo variable names into
839 * references to locations in the arrays Booleans, Numbers, and Strings ---
840 * precisely what's needed.
845 static void set_obsolete_termcaps(TERMTYPE *tp)
847 #include "capdefaults.c"