dump_entry.c revision 98503
150276Speter/****************************************************************************
298503Speter * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
3298503Speter *     and: Thomas E. Dickey 1996 on                                        *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter#define __INTERNAL_CAPS_VISIBLE
3650276Speter#include <progs.priv.h>
3750276Speter
3850276Speter#include "dump_entry.h"
3950276Speter#include "termsort.c"		/* this C file is generated */
4050276Speter#include <parametrized.h>	/* so is this */
4150276Speter
4298503SpeterMODULE_ID("$Id: dump_entry.c,v 1.58 2002/06/01 22:58:11 tom Exp $")
4350276Speter
4450276Speter#define INDENT			8
4550276Speter#define DISCARD(string) string = ABSENT_STRING
4662449Speter#define PRINTF (void) printf
4750276Speter
4862449Spetertypedef struct {
4962449Speter    char *text;
5062449Speter    size_t used;
5162449Speter    size_t size;
5262449Speter} DYNBUF;
5362449Speter
5450276Speterstatic int tversion;		/* terminfo version */
5550276Speterstatic int outform;		/* output format to use */
5650276Speterstatic int sortmode;		/* sort mode to use */
5750276Speterstatic int width = 60;		/* max line width for listings */
5850276Speterstatic int column;		/* current column, limited by 'width' */
5950276Speterstatic int oldcol;		/* last value of column before wrap */
6050276Speterstatic bool pretty;		/* true if we format if-then-else strings */
6150276Speter
6262449Speterstatic DYNBUF outbuf;
6362449Speterstatic DYNBUF tmpbuf;
6450276Speter
6550276Speter/* indirection pointers for implementing sort and display modes */
6650276Speterstatic const int *bool_indirect, *num_indirect, *str_indirect;
6762449Speterstatic NCURSES_CONST char *const *bool_names;
6862449Speterstatic NCURSES_CONST char *const *num_names;
6962449Speterstatic NCURSES_CONST char *const *str_names;
7050276Speter
7150276Speterstatic const char *separator, *trailer;
7250276Speter
7350276Speter/* cover various ports and variants of terminfo */
7450276Speter#define V_ALLCAPS	0	/* all capabilities (SVr4, XSI, ncurses) */
7550276Speter#define V_SVR1		1	/* SVR1, Ultrix */
7650276Speter#define V_HPUX		2	/* HP/UX */
7750276Speter#define V_AIX		3	/* AIX */
7850276Speter#define V_BSD		4	/* BSD */
7950276Speter
8062449Speter#if NCURSES_XNAMES
8162449Speter#define OBSOLETE(n) (!_nc_user_definable && (n[0] == 'O' && n[1] == 'T'))
8262449Speter#else
8350276Speter#define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
8462449Speter#endif
8550276Speter
8662449Speter#define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && OBSOLETE(n))
8762449Speter
8850276Speter#if NCURSES_XNAMES
8950276Speter#define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
9050276Speter#define NumIndirect(j)  ((j >= NUMCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
9150276Speter#define StrIndirect(j)  ((j >= STRCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
9250276Speter#else
9350276Speter#define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
9450276Speter#define NumIndirect(j)  ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
9550276Speter#define StrIndirect(j)  ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
9650276Speter#endif
9750276Speter
9862449Speterstatic void
9962449Speterstrncpy_DYN(DYNBUF * dst, const char *src, size_t need)
10062449Speter{
10162449Speter    size_t want = need + dst->used + 1;
10262449Speter    if (want > dst->size) {
10362449Speter	dst->size += (want + 1024);	/* be generous */
10462449Speter	dst->text = typeRealloc(char, dst->size, dst->text);
10562449Speter    }
10662449Speter    (void) strncpy(dst->text + dst->used, src, need);
10762449Speter    dst->used += need;
10862449Speter    dst->text[dst->used] = 0;
10962449Speter}
11062449Speter
11162449Speterstatic void
11262449Speterstrcpy_DYN(DYNBUF * dst, const char *src)
11362449Speter{
11462449Speter    if (src == 0) {
11562449Speter	dst->used = 0;
11662449Speter	strcpy_DYN(dst, "");
11762449Speter    } else {
11862449Speter	strncpy_DYN(dst, src, strlen(src));
11962449Speter    }
12062449Speter}
12162449Speter
12250276Speter#if NO_LEAKS
12362449Speterstatic void
12462449Speterfree_DYN(DYNBUF * p)
12550276Speter{
12662449Speter    if (p->text != 0)
12762449Speter	free(p->text);
12862449Speter    p->text = 0;
12962449Speter    p->size = 0;
13062449Speter    p->used = 0;
13150276Speter}
13262449Speter
13362449Spetervoid
13462449Speter_nc_leaks_dump_entry(void)
13562449Speter{
13662449Speter    free_DYN(&outbuf);
13762449Speter    free_DYN(&tmpbuf);
13862449Speter}
13950276Speter#endif
14050276Speter
14162449SpeterNCURSES_CONST char *
14262449Speternametrans(const char *name)
14350276Speter/* translate a capability name from termcap to terminfo */
14450276Speter{
14562449Speter    const struct name_table_entry *np;
14650276Speter
14750276Speter    if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0)
14862449Speter	switch (np->nte_type) {
14950276Speter	case BOOLEAN:
15050276Speter	    if (bool_from_termcap[np->nte_index])
15162449Speter		return (boolcodes[np->nte_index]);
15250276Speter	    break;
15350276Speter
15450276Speter	case NUMBER:
15550276Speter	    if (num_from_termcap[np->nte_index])
15662449Speter		return (numcodes[np->nte_index]);
15750276Speter	    break;
15850276Speter
15950276Speter	case STRING:
16050276Speter	    if (str_from_termcap[np->nte_index])
16162449Speter		return (strcodes[np->nte_index]);
16250276Speter	    break;
16350276Speter	}
16450276Speter
16562449Speter    return (0);
16650276Speter}
16750276Speter
16862449Spetervoid
16962449Speterdump_init(const char *version, int mode, int sort, int twidth, int traceval,
17098503Speter	  bool formatted)
17150276Speter/* set up for entry display */
17250276Speter{
17350276Speter    width = twidth;
17450276Speter    pretty = formatted;
17550276Speter
17650276Speter    /* versions */
17750276Speter    if (version == 0)
17850276Speter	tversion = V_ALLCAPS;
17950276Speter    else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
18098503Speter	     || !strcmp(version, "Ultrix"))
18150276Speter	tversion = V_SVR1;
18250276Speter    else if (!strcmp(version, "HP"))
18350276Speter	tversion = V_HPUX;
18450276Speter    else if (!strcmp(version, "AIX"))
18550276Speter	tversion = V_AIX;
18650276Speter    else if (!strcmp(version, "BSD"))
18750276Speter	tversion = V_BSD;
18850276Speter    else
18950276Speter	tversion = V_ALLCAPS;
19050276Speter
19150276Speter    /* implement display modes */
19262449Speter    switch (outform = mode) {
19350276Speter    case F_LITERAL:
19450276Speter    case F_TERMINFO:
19550276Speter	bool_names = boolnames;
19650276Speter	num_names = numnames;
19750276Speter	str_names = strnames;
19850276Speter	separator = twidth ? ", " : ",";
19950276Speter	trailer = "\n\t";
20050276Speter	break;
20150276Speter
20250276Speter    case F_VARIABLE:
20350276Speter	bool_names = boolfnames;
20450276Speter	num_names = numfnames;
20550276Speter	str_names = strfnames;
20650276Speter	separator = twidth ? ", " : ",";
20750276Speter	trailer = "\n\t";
20850276Speter	break;
20950276Speter
21050276Speter    case F_TERMCAP:
21150276Speter    case F_TCONVERR:
21250276Speter	bool_names = boolcodes;
21350276Speter	num_names = numcodes;
21450276Speter	str_names = strcodes;
21550276Speter	separator = ":";
21650276Speter	trailer = "\\\n\t:";
21750276Speter	break;
21850276Speter    }
21950276Speter
22050276Speter    /* implement sort modes */
22162449Speter    switch (sortmode = sort) {
22250276Speter    case S_NOSORT:
22350276Speter	if (traceval)
22450276Speter	    (void) fprintf(stderr,
22598503Speter			   "%s: sorting by term structure order\n", _nc_progname);
22650276Speter	break;
22750276Speter
22850276Speter    case S_TERMINFO:
22950276Speter	if (traceval)
23050276Speter	    (void) fprintf(stderr,
23198503Speter			   "%s: sorting by terminfo name order\n", _nc_progname);
23250276Speter	bool_indirect = bool_terminfo_sort;
23350276Speter	num_indirect = num_terminfo_sort;
23450276Speter	str_indirect = str_terminfo_sort;
23550276Speter	break;
23650276Speter
23750276Speter    case S_VARIABLE:
23850276Speter	if (traceval)
23950276Speter	    (void) fprintf(stderr,
24098503Speter			   "%s: sorting by C variable order\n", _nc_progname);
24150276Speter	bool_indirect = bool_variable_sort;
24250276Speter	num_indirect = num_variable_sort;
24350276Speter	str_indirect = str_variable_sort;
24450276Speter	break;
24550276Speter
24650276Speter    case S_TERMCAP:
24750276Speter	if (traceval)
24850276Speter	    (void) fprintf(stderr,
24998503Speter			   "%s: sorting by termcap name order\n", _nc_progname);
25050276Speter	bool_indirect = bool_termcap_sort;
25150276Speter	num_indirect = num_termcap_sort;
25250276Speter	str_indirect = str_termcap_sort;
25350276Speter	break;
25450276Speter    }
25550276Speter
25650276Speter    if (traceval)
25750276Speter	(void) fprintf(stderr,
25898503Speter		       "%s: width = %d, tversion = %d, outform = %d\n",
25998503Speter		       _nc_progname, width, tversion, outform);
26050276Speter}
26150276Speter
26262449Speterstatic TERMTYPE *cur_type;
26350276Speter
26462449Speterstatic int
26562449Speterdump_predicate(int type, int idx)
26650276Speter/* predicate function to use for ordinary decompilation */
26750276Speter{
26862449Speter    switch (type) {
26962449Speter    case BOOLEAN:
27062449Speter	return (cur_type->Booleans[idx] == FALSE)
27162449Speter	    ? FAIL : cur_type->Booleans[idx];
27250276Speter
27362449Speter    case NUMBER:
27462449Speter	return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
27562449Speter	    ? FAIL : cur_type->Numbers[idx];
27650276Speter
27762449Speter    case STRING:
27862449Speter	return (cur_type->Strings[idx] != ABSENT_STRING)
27962449Speter	    ? (int) TRUE : FAIL;
28062449Speter    }
28150276Speter
28262449Speter    return (FALSE);		/* pacify compiler */
28350276Speter}
28450276Speter
28562449Speterstatic void set_obsolete_termcaps(TERMTYPE * tp);
28650276Speter
28750276Speter/* is this the index of a function key string? */
28850276Speter#define FNKEY(i)	(((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268))
28950276Speter
29062449Speterstatic bool
29162449Speterversion_filter(int type, int idx)
29250276Speter/* filter out capabilities we may want to suppress */
29350276Speter{
29462449Speter    switch (tversion) {
29562449Speter    case V_ALLCAPS:		/* SVr4, XSI Curses */
29662449Speter	return (TRUE);
29750276Speter
29862449Speter    case V_SVR1:		/* System V Release 1, Ultrix */
29962449Speter	switch (type) {
30050276Speter	case BOOLEAN:
30150276Speter	    /* below and including xon_xoff */
30250276Speter	    return ((idx <= 20) ? TRUE : FALSE);
30350276Speter	case NUMBER:
30450276Speter	    /* below and including width_status_line */
30550276Speter	    return ((idx <= 7) ? TRUE : FALSE);
30650276Speter	case STRING:
30750276Speter	    /* below and including prtr_non */
30850276Speter	    return ((idx <= 144) ? TRUE : FALSE);
30950276Speter	}
31050276Speter	break;
31150276Speter
31250276Speter    case V_HPUX:		/* Hewlett-Packard */
31362449Speter	switch (type) {
31450276Speter	case BOOLEAN:
31550276Speter	    /* below and including xon_xoff */
31650276Speter	    return ((idx <= 20) ? TRUE : FALSE);
31750276Speter	case NUMBER:
31850276Speter	    /* below and including label_width */
31950276Speter	    return ((idx <= 10) ? TRUE : FALSE);
32050276Speter	case STRING:
32150276Speter	    if (idx <= 144)	/* below and including prtr_non */
32262449Speter		return (TRUE);
32350276Speter	    else if (FNKEY(idx))	/* function keys */
32462449Speter		return (TRUE);
32562449Speter	    else if (idx == 147 || idx == 156 || idx == 157)	/* plab_norm,label_on,label_off */
32662449Speter		return (TRUE);
32750276Speter	    else
32862449Speter		return (FALSE);
32950276Speter	}
33050276Speter	break;
33150276Speter
33250276Speter    case V_AIX:		/* AIX */
33362449Speter	switch (type) {
33450276Speter	case BOOLEAN:
33550276Speter	    /* below and including xon_xoff */
33650276Speter	    return ((idx <= 20) ? TRUE : FALSE);
33750276Speter	case NUMBER:
33850276Speter	    /* below and including width_status_line */
33950276Speter	    return ((idx <= 7) ? TRUE : FALSE);
34050276Speter	case STRING:
34150276Speter	    if (idx <= 144)	/* below and including prtr_non */
34262449Speter		return (TRUE);
34350276Speter	    else if (FNKEY(idx))	/* function keys */
34462449Speter		return (TRUE);
34550276Speter	    else
34662449Speter		return (FALSE);
34750276Speter	}
34850276Speter	break;
34950276Speter
35050276Speter    case V_BSD:		/* BSD */
35162449Speter	switch (type) {
35250276Speter	case BOOLEAN:
35350276Speter	    return bool_from_termcap[idx];
35450276Speter	case NUMBER:
35550276Speter	    return num_from_termcap[idx];
35650276Speter	case STRING:
35750276Speter	    return str_from_termcap[idx];
35850276Speter	}
35950276Speter	break;
36050276Speter    }
36150276Speter
36262449Speter    return (FALSE);		/* pacify the compiler */
36350276Speter}
36450276Speter
36562449Speterstatic void
36662449Speterforce_wrap(void)
36750276Speter{
36862449Speter    oldcol = column;
36962449Speter    strcpy_DYN(&outbuf, trailer);
37062449Speter    column = INDENT;
37150276Speter}
37250276Speter
37362449Speterstatic void
37462449Speterwrap_concat(const char *src)
37550276Speter{
37662449Speter    int need = strlen(src);
37762449Speter    int want = strlen(separator) + need;
37850276Speter
37962449Speter    if (column > INDENT
38062449Speter	&& column + want > width) {
38162449Speter	force_wrap();
38262449Speter    }
38362449Speter    strcpy_DYN(&outbuf, src);
38462449Speter    strcpy_DYN(&outbuf, separator);
38562449Speter    column += need;
38650276Speter}
38750276Speter
38850276Speter#define IGNORE_SEP_TRAIL(first,last,sep_trail) \
38950276Speter	if ((size_t)(last - first) > sizeof(sep_trail)-1 \
39050276Speter	 && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
39150276Speter	 	first += sizeof(sep_trail)-2
39250276Speter
39350276Speter/* Returns the nominal length of the buffer assuming it is termcap format,
39450276Speter * i.e., the continuation sequence is treated as a single character ":".
39550276Speter *
39650276Speter * There are several implementations of termcap which read the text into a
39750276Speter * fixed-size buffer.  Generally they strip the newlines from the text, but may
39850276Speter * not do it until after the buffer is read.  Also, "tc=" resolution may be
39950276Speter * expanded in the same buffer.  This function is useful for measuring the size
40050276Speter * of the best fixed-buffer implementation; the worst case may be much worse.
40150276Speter */
40250276Speter#ifdef TEST_TERMCAP_LENGTH
40362449Speterstatic int
40462449Spetertermcap_length(const char *src)
40550276Speter{
40662449Speter    static const char pattern[] = ":\\\n\t:";
40750276Speter
40862449Speter    int len = 0;
40962449Speter    const char *const t = src + strlen(src);
41050276Speter
41162449Speter    while (*src != '\0') {
41262449Speter	IGNORE_SEP_TRAIL(src, t, pattern);
41362449Speter	src++;
41462449Speter	len++;
41562449Speter    }
41662449Speter    return len;
41750276Speter}
41850276Speter#else
41950276Speter#define termcap_length(src) strlen(src)
42050276Speter#endif
42150276Speter
42262449Speterstatic char *
42362449Speterfmt_complex(char *src, int level)
42450276Speter{
42562449Speter    int percent = 0;
42662449Speter    int n;
42762449Speter    bool if_then = strstr(src, "%?") != 0;
42862449Speter    bool params = !if_then && (strlen(src) > 50) && (strstr(src, "%p") != 0);
42950276Speter
43062449Speter    while (*src != '\0') {
43162449Speter	switch (*src) {
43262449Speter	case '\\':
43362449Speter	    percent = 0;
43462449Speter	    strncpy_DYN(&tmpbuf, src++, 1);
43562449Speter	    break;
43662449Speter	case '%':
43762449Speter	    percent = 1;
43862449Speter	    break;
43962449Speter	case '?':		/* "if" */
44062449Speter	case 't':		/* "then" */
44162449Speter	case 'e':		/* "else" */
44262449Speter	    if (percent) {
44362449Speter		percent = 0;
44462449Speter		tmpbuf.text[tmpbuf.used - 1] = '\n';
44562449Speter		/* treat a "%e%?" as else-if, on the same level */
44662449Speter		if (!strncmp(src, "e%?", 3)) {
44762449Speter		    for (n = 0; n < level; n++)
44862449Speter			strncpy_DYN(&tmpbuf, "\t", 1);
44962449Speter		    strncpy_DYN(&tmpbuf, "%", 1);
45062449Speter		    strncpy_DYN(&tmpbuf, src, 3);
45162449Speter		    src += 3;
45262449Speter		} else {
45362449Speter		    for (n = 0; n <= level; n++)
45462449Speter			strncpy_DYN(&tmpbuf, "\t", 1);
45562449Speter		    strncpy_DYN(&tmpbuf, "%", 1);
45662449Speter		    strncpy_DYN(&tmpbuf, src, 1);
45762449Speter		    if (*src++ == '?') {
45862449Speter			src = fmt_complex(src, level + 1);
45962449Speter		    } else if (level == 1) {
46062449Speter			_nc_warning("%%%c without %%?", *src);
46162449Speter		    }
46250276Speter		}
46362449Speter		continue;
46462449Speter	    }
46562449Speter	    break;
46662449Speter	case ';':		/* "endif" */
46762449Speter	    if (percent) {
46862449Speter		percent = 0;
46962449Speter		if (level > 1) {
47062449Speter		    tmpbuf.text[tmpbuf.used - 1] = '\n';
47162449Speter		    for (n = 0; n < level; n++)
47262449Speter			strncpy_DYN(&tmpbuf, "\t", 1);
47362449Speter		    strncpy_DYN(&tmpbuf, "%", 1);
47462449Speter		    strncpy_DYN(&tmpbuf, src++, 1);
47562449Speter		    return src;
47662449Speter		}
47762449Speter		_nc_warning("%%; without %%?");
47862449Speter	    }
47962449Speter	    break;
48062449Speter	case 'p':
48162449Speter	    if (percent && params) {
48262449Speter		tmpbuf.text[tmpbuf.used - 1] = '\n';
48362449Speter		for (n = 0; n <= level; n++)
48462449Speter		    strncpy_DYN(&tmpbuf, "\t", 1);
48562449Speter		strncpy_DYN(&tmpbuf, "%", 1);
48662449Speter	    }
48762449Speter	    percent = 0;
48862449Speter	    break;
48962449Speter	default:
49062449Speter	    percent = 0;
49162449Speter	    break;
49250276Speter	}
49362449Speter	strncpy_DYN(&tmpbuf, src++, 1);
49462449Speter    }
49562449Speter    return src;
49650276Speter}
49750276Speter
49862449Speterint
49962449Speterfmt_entry(TERMTYPE * tterm,
50098503Speter	  int (*pred) (int type, int idx),
50198503Speter	  bool suppress_untranslatable,
50298503Speter	  bool infodump,
50398503Speter	  int numbers)
50450276Speter{
50562449Speter    int i, j;
50662449Speter    char buffer[MAX_TERMINFO_LENGTH];
50762449Speter    NCURSES_CONST char *name;
50862449Speter    int predval, len;
50962449Speter    int num_bools = 0;
51062449Speter    int num_values = 0;
51162449Speter    int num_strings = 0;
51262449Speter    bool outcount = 0;
51350276Speter
51450276Speter#define WRAP_CONCAT	\
51550276Speter	wrap_concat(buffer); \
51650276Speter	outcount = TRUE
51750276Speter
51850276Speter    len = 12;			/* terminfo file-header */
51950276Speter
52050276Speter    if (pred == 0) {
52150276Speter	cur_type = tterm;
52250276Speter	pred = dump_predicate;
52350276Speter    }
52450276Speter
52562449Speter    strcpy_DYN(&outbuf, 0);
52662449Speter    strcpy_DYN(&outbuf, tterm->term_names);
52762449Speter    strcpy_DYN(&outbuf, separator);
52862449Speter    column = outbuf.used;
52950276Speter    force_wrap();
53050276Speter
53162449Speter    for_each_boolean(j, tterm) {
53250276Speter	i = BoolIndirect(j);
53362449Speter	name = ExtBoolname(tterm, i, bool_names);
53450276Speter
53550276Speter	if (!version_filter(BOOLEAN, i))
53650276Speter	    continue;
53762449Speter	else if (isObsolete(outform, name))
53850276Speter	    continue;
53950276Speter
54050276Speter	predval = pred(BOOLEAN, i);
54150276Speter	if (predval != FAIL) {
54250276Speter	    (void) strcpy(buffer, name);
54350276Speter	    if (predval <= 0)
54450276Speter		(void) strcat(buffer, "@");
54550276Speter	    else if (i + 1 > num_bools)
54650276Speter		num_bools = i + 1;
54750276Speter	    WRAP_CONCAT;
54850276Speter	}
54950276Speter    }
55050276Speter
55150276Speter    if (column != INDENT)
55250276Speter	force_wrap();
55350276Speter
55462449Speter    for_each_number(j, tterm) {
55550276Speter	i = NumIndirect(j);
55662449Speter	name = ExtNumname(tterm, i, num_names);
55750276Speter
55850276Speter	if (!version_filter(NUMBER, i))
55950276Speter	    continue;
56062449Speter	else if (isObsolete(outform, name))
56150276Speter	    continue;
56250276Speter
56350276Speter	predval = pred(NUMBER, i);
56450276Speter	if (predval != FAIL) {
56550276Speter	    if (tterm->Numbers[i] < 0) {
56650276Speter		sprintf(buffer, "%s@", name);
56750276Speter	    } else {
56850276Speter		sprintf(buffer, "%s#%d", name, tterm->Numbers[i]);
56950276Speter		if (i + 1 > num_values)
57050276Speter		    num_values = i + 1;
57150276Speter	    }
57250276Speter	    WRAP_CONCAT;
57350276Speter	}
57450276Speter    }
57550276Speter
57650276Speter    if (column != INDENT)
57750276Speter	force_wrap();
57850276Speter
57950276Speter    len += num_bools
58062449Speter	+ num_values * 2
58162449Speter	+ strlen(tterm->term_names) + 1;
58250276Speter    if (len & 1)
58362449Speter	len++;
58450276Speter
58562449Speter#undef CUR
58662449Speter#define CUR tterm->
58762449Speter    if (outform == F_TERMCAP) {
58862449Speter	if (termcap_reset != ABSENT_STRING) {
58962449Speter	    if (init_3string != ABSENT_STRING
59062449Speter		&& !strcmp(init_3string, termcap_reset))
59162449Speter		DISCARD(init_3string);
59262449Speter
59362449Speter	    if (reset_2string != ABSENT_STRING
59462449Speter		&& !strcmp(reset_2string, termcap_reset))
59562449Speter		DISCARD(reset_2string);
59662449Speter	}
59762449Speter    }
59862449Speter
59950276Speter    for_each_string(j, tterm) {
60050276Speter	i = StrIndirect(j);
60162449Speter	name = ExtStrname(tterm, i, str_names);
60250276Speter
60350276Speter	if (!version_filter(STRING, i))
60450276Speter	    continue;
60562449Speter	else if (isObsolete(outform, name))
60650276Speter	    continue;
60750276Speter
60850276Speter	/*
60950276Speter	 * Some older versions of vi want rmir/smir to be defined
61050276Speter	 * for ich/ich1 to work.  If they're not defined, force
61150276Speter	 * them to be output as defined and empty.
61250276Speter	 */
61362449Speter	if (outform == F_TERMCAP) {
61462449Speter	    if (insert_character || parm_ich) {
61550276Speter		if (&tterm->Strings[i] == &enter_insert_mode
61662449Speter		    && enter_insert_mode == ABSENT_STRING) {
61750276Speter		    (void) strcpy(buffer, "im=");
61862449Speter		    WRAP_CONCAT;
61962449Speter		    continue;
62050276Speter		}
62150276Speter
62250276Speter		if (&tterm->Strings[i] == &exit_insert_mode
62362449Speter		    && exit_insert_mode == ABSENT_STRING) {
62450276Speter		    (void) strcpy(buffer, "ei=");
62562449Speter		    WRAP_CONCAT;
62662449Speter		    continue;
62750276Speter		}
62850276Speter	    }
62950276Speter	}
63050276Speter
63150276Speter	predval = pred(STRING, i);
63250276Speter	buffer[0] = '\0';
63362449Speter
63450276Speter	if (predval != FAIL) {
63550276Speter	    if (tterm->Strings[i] != ABSENT_STRING
63662449Speter		&& i + 1 > num_strings)
63750276Speter		num_strings = i + 1;
63862449Speter
63962449Speter	    if (!VALID_STRING(tterm->Strings[i])) {
64050276Speter		sprintf(buffer, "%s@", name);
64162449Speter		WRAP_CONCAT;
64262449Speter	    } else if (outform == F_TERMCAP || outform == F_TCONVERR) {
64398503Speter		int params = ((i < (int) SIZEOF(parametrized))
64498503Speter			      ? parametrized[i]
64598503Speter			      : 0);
64662449Speter		char *srccap = _nc_tic_expand(tterm->Strings[i], TRUE, numbers);
64766963Speter		char *cv = _nc_infotocap(name, srccap, params);
64850276Speter
64962449Speter		if (cv == 0) {
65062449Speter		    if (outform == F_TCONVERR) {
65162449Speter			sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!",
65298503Speter				name, srccap);
65362449Speter		    } else if (suppress_untranslatable) {
65450276Speter			continue;
65562449Speter		    } else {
65662449Speter			char *s = srccap, *d = buffer;
65762449Speter			sprintf(d, "..%s=", name);
65862449Speter			d += strlen(d);
65962449Speter			while ((*d = *s++) != 0) {
66062449Speter			    if (*d == ':') {
66162449Speter				*d++ = '\\';
66262449Speter				*d = ':';
66362449Speter			    } else if (*d == '\\') {
66462449Speter				*++d = *s++;
66562449Speter			    }
66662449Speter			    d++;
66762449Speter			}
66862449Speter		    }
66962449Speter		} else {
67062449Speter		    sprintf(buffer, "%s=%s", name, cv);
67150276Speter		}
67250276Speter		len += strlen(tterm->Strings[i]) + 1;
67362449Speter		WRAP_CONCAT;
67462449Speter	    } else {
67562449Speter		char *src = _nc_tic_expand(tterm->Strings[i],
67698503Speter					   outform == F_TERMINFO, numbers);
67762449Speter
67862449Speter		strcpy_DYN(&tmpbuf, 0);
67962449Speter		strcpy_DYN(&tmpbuf, name);
68062449Speter		strcpy_DYN(&tmpbuf, "=");
68162449Speter		if (pretty
68262449Speter		    && (outform == F_TERMINFO
68362449Speter			|| outform == F_VARIABLE)) {
68462449Speter		    fmt_complex(src, 1);
68562449Speter		} else {
68662449Speter		    strcpy_DYN(&tmpbuf, src);
68762449Speter		}
68850276Speter		len += strlen(tterm->Strings[i]) + 1;
68962449Speter		wrap_concat(tmpbuf.text);
69062449Speter		outcount = TRUE;
69150276Speter	    }
69250276Speter	}
69350276Speter    }
69450276Speter    len += num_strings * 2;
69550276Speter
69650276Speter    /*
69750276Speter     * This piece of code should be an effective inverse of the functions
69850276Speter     * postprocess_terminfo and postprocess_terminfo in parse_entry.c.
69950276Speter     * Much more work should be done on this to support dumping termcaps.
70050276Speter     */
70162449Speter    if (tversion == V_HPUX) {
70262449Speter	if (memory_lock) {
70350276Speter	    (void) sprintf(buffer, "meml=%s", memory_lock);
70450276Speter	    WRAP_CONCAT;
70550276Speter	}
70662449Speter	if (memory_unlock) {
70750276Speter	    (void) sprintf(buffer, "memu=%s", memory_unlock);
70850276Speter	    WRAP_CONCAT;
70950276Speter	}
71062449Speter    } else if (tversion == V_AIX) {
71162449Speter	if (VALID_STRING(acs_chars)) {
71262449Speter	    bool box_ok = TRUE;
71362449Speter	    const char *acstrans = "lqkxjmwuvtn";
71462449Speter	    const char *cp;
71562449Speter	    char *tp, *sp, boxchars[11];
71650276Speter
71750276Speter	    tp = boxchars;
71862449Speter	    for (cp = acstrans; *cp; cp++) {
71950276Speter		sp = strchr(acs_chars, *cp);
72050276Speter		if (sp)
72150276Speter		    *tp++ = sp[1];
72262449Speter		else {
72350276Speter		    box_ok = FALSE;
72450276Speter		    break;
72550276Speter		}
72650276Speter	    }
72750276Speter	    tp[0] = '\0';
72850276Speter
72962449Speter	    if (box_ok) {
73050276Speter		(void) strcpy(buffer, "box1=");
73162449Speter		(void) strcat(buffer, _nc_tic_expand(boxchars,
73298503Speter						     outform == F_TERMINFO, numbers));
73350276Speter		WRAP_CONCAT;
73450276Speter	    }
73550276Speter	}
73650276Speter    }
73750276Speter
73850276Speter    /*
73950276Speter     * kludge: trim off trailer to avoid an extra blank line
74050276Speter     * in infocmp -u output when there are no string differences
74150276Speter     */
74262449Speter    if (outcount) {
74362449Speter	bool trimmed = FALSE;
74462449Speter	j = outbuf.used;
74550276Speter	if (j >= 2
74662449Speter	    && outbuf.text[j - 1] == '\t'
74762449Speter	    && outbuf.text[j - 2] == '\n') {
74862449Speter	    outbuf.used -= 2;
74962449Speter	    trimmed = TRUE;
75050276Speter	} else if (j >= 4
75198503Speter		   && outbuf.text[j - 1] == ':'
75298503Speter		   && outbuf.text[j - 2] == '\t'
75398503Speter		   && outbuf.text[j - 3] == '\n'
75498503Speter		   && outbuf.text[j - 4] == '\\') {
75562449Speter	    outbuf.used -= 4;
75662449Speter	    trimmed = TRUE;
75750276Speter	}
75862449Speter	if (trimmed) {
75962449Speter	    outbuf.text[outbuf.used] = '\0';
76062449Speter	    column = oldcol;
76162449Speter	}
76250276Speter    }
76350276Speter#if 0
76450276Speter    fprintf(stderr, "num_bools = %d\n", num_bools);
76550276Speter    fprintf(stderr, "num_values = %d\n", num_values);
76650276Speter    fprintf(stderr, "num_strings = %d\n", num_strings);
76750276Speter    fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
76898503Speter	    tterm->term_names, len, outbuf.used, outbuf.text);
76950276Speter#endif
77050276Speter    /*
77150276Speter     * Here's where we use infodump to trigger a more stringent length check
77250276Speter     * for termcap-translation purposes.
77350276Speter     * Return the length of the raw entry, without tc= expansions,
77450276Speter     * It gives an idea of which entries are deadly to even *scan past*,
77550276Speter     * as opposed to *use*.
77650276Speter     */
77776726Speter    return (infodump ? len : (int) termcap_length(outbuf.text));
77850276Speter}
77950276Speter
78098503Speterstatic bool
78198503Speterkill_string(TERMTYPE * tterm, char *cap)
78298503Speter{
78398503Speter    int n;
78498503Speter    for (n = 0; n < tterm->num_Strings; ++n) {
78598503Speter	if (cap == tterm->Strings[n]) {
78698503Speter	    tterm->Strings[n] = ABSENT_STRING;
78798503Speter	    return TRUE;
78898503Speter	}
78998503Speter    }
79098503Speter    return FALSE;
79198503Speter}
79298503Speter
79398503Speterstatic char *
79498503Speterfind_string(TERMTYPE * tterm, char *name)
79598503Speter{
79698503Speter    int n;
79798503Speter    for (n = 0; n < tterm->num_Strings; ++n) {
79898503Speter	if (version_filter(STRING, n)
79998503Speter	    && !strcmp(name, strnames[n])) {
80098503Speter	    char *cap = tterm->Strings[n];
80198503Speter	    if (VALID_STRING(cap)) {
80298503Speter		return cap;
80398503Speter	    }
80498503Speter	    break;
80598503Speter	}
80698503Speter    }
80798503Speter    return ABSENT_STRING;
80898503Speter}
80998503Speter
81098503Speter/*
81198503Speter * This is used to remove function-key labels from a termcap entry to
81298503Speter * make it smaller.
81398503Speter */
81498503Speterstatic int
81598503Speterkill_labels(TERMTYPE * tterm, int target)
81698503Speter{
81798503Speter    int n;
81898503Speter    int result = 0;
81998503Speter    char *cap;
82098503Speter    char name[10];
82198503Speter
82298503Speter    for (n = 0; n <= 10; ++n) {
82398503Speter	sprintf(name, "lf%d", n);
82498503Speter	if ((cap = find_string(tterm, name)) != ABSENT_STRING
82598503Speter	    && kill_string(tterm, cap)) {
82698503Speter	    target -= (strlen(cap) + 5);
82798503Speter	    ++result;
82898503Speter	    if (target < 0)
82998503Speter		break;
83098503Speter	}
83198503Speter    }
83298503Speter    return result;
83398503Speter}
83498503Speter
83598503Speter/*
83698503Speter * This is used to remove function-key definitions from a termcap entry to
83798503Speter * make it smaller.
83898503Speter */
83998503Speterstatic int
84098503Speterkill_fkeys(TERMTYPE * tterm, int target)
84198503Speter{
84298503Speter    int n;
84398503Speter    int result = 0;
84498503Speter    char *cap;
84598503Speter    char name[10];
84698503Speter
84798503Speter    for (n = 60; n >= 0; --n) {
84898503Speter	sprintf(name, "kf%d", n);
84998503Speter	if ((cap = find_string(tterm, name)) != ABSENT_STRING
85098503Speter	    && kill_string(tterm, cap)) {
85198503Speter	    target -= (strlen(cap) + 5);
85298503Speter	    ++result;
85398503Speter	    if (target < 0)
85498503Speter		break;
85598503Speter	}
85698503Speter    }
85798503Speter    return result;
85898503Speter}
85998503Speter
86062449Speterint
86198503Speterdump_entry(TERMTYPE * tterm,
86298503Speter	   bool limited,
86398503Speter	   int numbers,
86498503Speter	   int (*pred) (int type, int idx))
86550276Speter/* dump a single entry */
86650276Speter{
86762449Speter    int len, critlen;
86862449Speter    const char *legend;
86962449Speter    bool infodump;
87050276Speter
87162449Speter    if (outform == F_TERMCAP || outform == F_TCONVERR) {
87250276Speter	critlen = MAX_TERMCAP_LENGTH;
87350276Speter	legend = "older termcap";
87450276Speter	infodump = FALSE;
87550276Speter	set_obsolete_termcaps(tterm);
87662449Speter    } else {
87750276Speter	critlen = MAX_TERMINFO_LENGTH;
87850276Speter	legend = "terminfo";
87950276Speter	infodump = TRUE;
88050276Speter    }
88150276Speter
88262449Speter    if (((len = fmt_entry(tterm, pred, FALSE, infodump, numbers)) > critlen)
88362449Speter	&& limited) {
88462449Speter	PRINTF("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
88598503Speter	       critlen);
88662449Speter	if ((len = fmt_entry(tterm, pred, TRUE, infodump, numbers)) > critlen) {
88750276Speter	    /*
88850276Speter	     * We pick on sgr because it's a nice long string capability that
88962449Speter	     * is really just an optimization hack.  Another good candidate is
89062449Speter	     * acsc since it is both long and unused by BSD termcap.
89150276Speter	     */
89250276Speter	    char *oldsgr = set_attributes;
89362449Speter	    char *oldacsc = acs_chars;
89450276Speter	    set_attributes = ABSENT_STRING;
89562449Speter	    PRINTF("# (sgr removed to fit entry within %d bytes)\n",
89698503Speter		   critlen);
89762449Speter	    if ((len = fmt_entry(tterm, pred, TRUE, infodump, numbers)) > critlen) {
89862449Speter		acs_chars = ABSENT_STRING;
89962449Speter		PRINTF("# (acsc removed to fit entry within %d bytes)\n",
90098503Speter		       critlen);
90162449Speter	    }
90262449Speter	    if ((len = fmt_entry(tterm, pred, TRUE, infodump, numbers)) > critlen) {
90350276Speter		int oldversion = tversion;
90450276Speter
90550276Speter		tversion = V_BSD;
90662449Speter		PRINTF("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
90798503Speter		       critlen);
90850276Speter
90998503Speter		len = fmt_entry(tterm, pred, TRUE, infodump, numbers);
91098503Speter		if (len > critlen
91198503Speter		    && kill_labels(tterm, len - critlen)) {
91298503Speter		    PRINTF("# (some labels capabilities suppressed to fit entry within %d bytes)\n",
91398503Speter			   critlen);
91498503Speter		    len = fmt_entry(tterm, pred, TRUE, infodump, numbers);
91598503Speter		}
91698503Speter		if (len > critlen
91798503Speter		    && kill_fkeys(tterm, len - critlen)) {
91898503Speter		    PRINTF("# (some function-key capabilities suppressed to fit entry within %d bytes)\n",
91998503Speter			   critlen);
92098503Speter		    len = fmt_entry(tterm, pred, TRUE, infodump, numbers);
92198503Speter		}
92298503Speter		if (len > critlen) {
92350276Speter		    (void) fprintf(stderr,
92498503Speter				   "warning: %s entry is %d bytes long\n",
92598503Speter				   _nc_first_name(tterm->term_names),
92698503Speter				   len);
92762449Speter		    PRINTF(
92898503Speter			      "# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
92998503Speter			      len, legend);
93050276Speter		}
93150276Speter		tversion = oldversion;
93250276Speter	    }
93350276Speter	    set_attributes = oldsgr;
93462449Speter	    acs_chars = oldacsc;
93550276Speter	}
93650276Speter    }
93750276Speter
93862449Speter    (void) fputs(outbuf.text, stdout);
93950276Speter    return len;
94050276Speter}
94150276Speter
94262449Speterint
94362449Speterdump_uses(const char *name, bool infodump)
94450276Speter/* dump "use=" clauses in the appropriate format */
94550276Speter{
94650276Speter    char buffer[MAX_TERMINFO_LENGTH];
94750276Speter
94862449Speter    strcpy_DYN(&outbuf, 0);
94962449Speter    (void) sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name);
95050276Speter    wrap_concat(buffer);
95162449Speter    (void) fputs(outbuf.text, stdout);
95262449Speter    return outbuf.used;
95350276Speter}
95450276Speter
95562449Spetervoid
95662449Spetercompare_entry(void (*hook) (int t, int i, const char *name), TERMTYPE * tp
95798503Speter	      GCC_UNUSED, bool quiet)
95850276Speter/* compare two entries */
95950276Speter{
96062449Speter    int i, j;
96162449Speter    NCURSES_CONST char *name;
96250276Speter
96362449Speter    if (!quiet)
96462449Speter	fputs("    comparing booleans.\n", stdout);
96562449Speter    for_each_boolean(j, tp) {
96650276Speter	i = BoolIndirect(j);
96762449Speter	name = ExtBoolname(tp, i, bool_names);
96850276Speter
96962449Speter	if (isObsolete(outform, name))
97050276Speter	    continue;
97150276Speter
97262449Speter	(*hook) (CMP_BOOLEAN, i, name);
97350276Speter    }
97450276Speter
97562449Speter    if (!quiet)
97662449Speter	fputs("    comparing numbers.\n", stdout);
97762449Speter    for_each_number(j, tp) {
97850276Speter	i = NumIndirect(j);
97962449Speter	name = ExtNumname(tp, i, num_names);
98050276Speter
98162449Speter	if (isObsolete(outform, name))
98250276Speter	    continue;
98350276Speter
98462449Speter	(*hook) (CMP_NUMBER, i, name);
98550276Speter    }
98650276Speter
98762449Speter    if (!quiet)
98862449Speter	fputs("    comparing strings.\n", stdout);
98962449Speter    for_each_string(j, tp) {
99050276Speter	i = StrIndirect(j);
99162449Speter	name = ExtStrname(tp, i, str_names);
99250276Speter
99362449Speter	if (isObsolete(outform, name))
99450276Speter	    continue;
99550276Speter
99662449Speter	(*hook) (CMP_STRING, i, name);
99750276Speter    }
99862449Speter
99962449Speter    /* (void) fputs("    comparing use entries.\n", stdout); */
100062449Speter    (*hook) (CMP_USE, 0, "use");
100162449Speter
100250276Speter}
100350276Speter
100450276Speter#define NOTSET(s)	((s) == 0)
100550276Speter
100650276Speter/*
100750276Speter * This bit of legerdemain turns all the terminfo variable names into
100850276Speter * references to locations in the arrays Booleans, Numbers, and Strings ---
100950276Speter * precisely what's needed.
101050276Speter */
101150276Speter#undef CUR
101250276Speter#define CUR tp->
101350276Speter
101462449Speterstatic void
101562449Speterset_obsolete_termcaps(TERMTYPE * tp)
101650276Speter{
101750276Speter#include "capdefaults.c"
101850276Speter}
101950276Speter
102050276Speter/*
102150276Speter * Convert an alternate-character-set string to canonical form: sorted and
102250276Speter * unique.
102350276Speter */
102462449Spetervoid
102562449Speterrepair_acsc(TERMTYPE * tp)
102650276Speter{
102762449Speter    if (VALID_STRING(acs_chars)) {
102862449Speter	size_t n, m;
102962449Speter	char mapped[256];
103062449Speter	char extra = 0;
103162449Speter	unsigned source;
103262449Speter	unsigned target;
103362449Speter	bool fix_needed = FALSE;
103450276Speter
103562449Speter	for (n = 0, source = 0; acs_chars[n] != 0; n++) {
103662449Speter	    target = acs_chars[n];
103762449Speter	    if (source >= target) {
103862449Speter		fix_needed = TRUE;
103962449Speter		break;
104062449Speter	    }
104162449Speter	    source = target;
104262449Speter	    if (acs_chars[n + 1])
104362449Speter		n++;
104462449Speter	}
104562449Speter	if (fix_needed) {
104662449Speter	    memset(mapped, 0, sizeof(mapped));
104762449Speter	    for (n = 0; acs_chars[n] != 0; n++) {
104862449Speter		source = acs_chars[n];
104962449Speter		if ((target = (unsigned char) acs_chars[n + 1]) != 0) {
105062449Speter		    mapped[source] = target;
105162449Speter		    n++;
105262449Speter		} else {
105362449Speter		    extra = source;
105450276Speter		}
105550276Speter	    }
105662449Speter	    for (n = m = 0; n < sizeof(mapped); n++) {
105762449Speter		if (mapped[n]) {
105862449Speter		    acs_chars[m++] = n;
105962449Speter		    acs_chars[m++] = mapped[n];
106050276Speter		}
106150276Speter	    }
106262449Speter	    if (extra)
106362449Speter		acs_chars[m++] = extra;		/* garbage in, garbage out */
106462449Speter	    acs_chars[m] = 0;
106550276Speter	}
106662449Speter    }
106750276Speter}
1068