150276Speter/****************************************************************************
2178866Srafan * Copyright (c) 1998-2007,2008 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>                         *
32184989Srafan *     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
42184989SrafanMODULE_ID("$Id: dump_entry.c,v 1.88 2008/08/04 12:36:12 tom Exp $")
4350276Speter
4450276Speter#define INDENT			8
4550276Speter#define DISCARD(string) string = ABSENT_STRING
4662449Speter#define PRINTF (void) printf
4750276Speter
48184989Srafan#define OkIndex(index,array) ((int)(index) >= 0 && (int)(index) < (int) SIZEOF(array))
49184989Srafan
5062449Spetertypedef struct {
5162449Speter    char *text;
5262449Speter    size_t used;
5362449Speter    size_t size;
5462449Speter} DYNBUF;
5562449Speter
5650276Speterstatic int tversion;		/* terminfo version */
5750276Speterstatic int outform;		/* output format to use */
5850276Speterstatic int sortmode;		/* sort mode to use */
5950276Speterstatic int width = 60;		/* max line width for listings */
6050276Speterstatic int column;		/* current column, limited by 'width' */
6150276Speterstatic int oldcol;		/* last value of column before wrap */
6250276Speterstatic bool pretty;		/* true if we format if-then-else strings */
6350276Speter
64166124Srafanstatic char *save_sgr;
65166124Srafan
6662449Speterstatic DYNBUF outbuf;
6762449Speterstatic DYNBUF tmpbuf;
6850276Speter
6950276Speter/* indirection pointers for implementing sort and display modes */
70166124Srafanstatic const PredIdx *bool_indirect, *num_indirect, *str_indirect;
7162449Speterstatic NCURSES_CONST char *const *bool_names;
7262449Speterstatic NCURSES_CONST char *const *num_names;
7362449Speterstatic NCURSES_CONST char *const *str_names;
7450276Speter
7550276Speterstatic const char *separator, *trailer;
7650276Speter
7750276Speter/* cover various ports and variants of terminfo */
7850276Speter#define V_ALLCAPS	0	/* all capabilities (SVr4, XSI, ncurses) */
7950276Speter#define V_SVR1		1	/* SVR1, Ultrix */
8050276Speter#define V_HPUX		2	/* HP/UX */
8150276Speter#define V_AIX		3	/* AIX */
8250276Speter#define V_BSD		4	/* BSD */
8350276Speter
8462449Speter#if NCURSES_XNAMES
8562449Speter#define OBSOLETE(n) (!_nc_user_definable && (n[0] == 'O' && n[1] == 'T'))
8662449Speter#else
8750276Speter#define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
8862449Speter#endif
8950276Speter
9062449Speter#define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && OBSOLETE(n))
9162449Speter
9250276Speter#if NCURSES_XNAMES
9350276Speter#define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
9450276Speter#define NumIndirect(j)  ((j >= NUMCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
9550276Speter#define StrIndirect(j)  ((j >= STRCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
9650276Speter#else
9750276Speter#define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
9850276Speter#define NumIndirect(j)  ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
9950276Speter#define StrIndirect(j)  ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
10050276Speter#endif
10150276Speter
10262449Speterstatic void
10362449Speterstrncpy_DYN(DYNBUF * dst, const char *src, size_t need)
10462449Speter{
10562449Speter    size_t want = need + dst->used + 1;
10662449Speter    if (want > dst->size) {
10762449Speter	dst->size += (want + 1024);	/* be generous */
10862449Speter	dst->text = typeRealloc(char, dst->size, dst->text);
10962449Speter    }
11062449Speter    (void) strncpy(dst->text + dst->used, src, need);
11162449Speter    dst->used += need;
11262449Speter    dst->text[dst->used] = 0;
11362449Speter}
11462449Speter
11562449Speterstatic void
11662449Speterstrcpy_DYN(DYNBUF * dst, const char *src)
11762449Speter{
11862449Speter    if (src == 0) {
11962449Speter	dst->used = 0;
12062449Speter	strcpy_DYN(dst, "");
12162449Speter    } else {
12262449Speter	strncpy_DYN(dst, src, strlen(src));
12362449Speter    }
12462449Speter}
12562449Speter
12650276Speter#if NO_LEAKS
12762449Speterstatic void
12862449Speterfree_DYN(DYNBUF * p)
12950276Speter{
13062449Speter    if (p->text != 0)
13162449Speter	free(p->text);
13262449Speter    p->text = 0;
13362449Speter    p->size = 0;
13462449Speter    p->used = 0;
13550276Speter}
13662449Speter
13762449Spetervoid
13862449Speter_nc_leaks_dump_entry(void)
13962449Speter{
14062449Speter    free_DYN(&outbuf);
14162449Speter    free_DYN(&tmpbuf);
14262449Speter}
14350276Speter#endif
14450276Speter
145184989Srafan#define NameTrans(check,result) \
146184989Srafan	    if (OkIndex(np->nte_index, check) \
147184989Srafan		&& check[np->nte_index]) \
148184989Srafan		return (result[np->nte_index])
149184989Srafan
15062449SpeterNCURSES_CONST char *
15162449Speternametrans(const char *name)
15250276Speter/* translate a capability name from termcap to terminfo */
15350276Speter{
15462449Speter    const struct name_table_entry *np;
15550276Speter
15650276Speter    if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0)
15762449Speter	switch (np->nte_type) {
15850276Speter	case BOOLEAN:
159184989Srafan	    NameTrans(bool_from_termcap, boolcodes);
16050276Speter	    break;
16150276Speter
16250276Speter	case NUMBER:
163184989Srafan	    NameTrans(num_from_termcap, numcodes);
16450276Speter	    break;
16550276Speter
16650276Speter	case STRING:
167184989Srafan	    NameTrans(str_from_termcap, strcodes);
16850276Speter	    break;
16950276Speter	}
17050276Speter
17162449Speter    return (0);
17250276Speter}
17350276Speter
17462449Spetervoid
17562449Speterdump_init(const char *version, int mode, int sort, int twidth, int traceval,
17698503Speter	  bool formatted)
17750276Speter/* set up for entry display */
17850276Speter{
17950276Speter    width = twidth;
18050276Speter    pretty = formatted;
18150276Speter
18250276Speter    /* versions */
18350276Speter    if (version == 0)
18450276Speter	tversion = V_ALLCAPS;
18550276Speter    else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
18698503Speter	     || !strcmp(version, "Ultrix"))
18750276Speter	tversion = V_SVR1;
18850276Speter    else if (!strcmp(version, "HP"))
18950276Speter	tversion = V_HPUX;
19050276Speter    else if (!strcmp(version, "AIX"))
19150276Speter	tversion = V_AIX;
19250276Speter    else if (!strcmp(version, "BSD"))
19350276Speter	tversion = V_BSD;
19450276Speter    else
19550276Speter	tversion = V_ALLCAPS;
19650276Speter
19750276Speter    /* implement display modes */
19862449Speter    switch (outform = mode) {
19950276Speter    case F_LITERAL:
20050276Speter    case F_TERMINFO:
20150276Speter	bool_names = boolnames;
20250276Speter	num_names = numnames;
20350276Speter	str_names = strnames;
20450276Speter	separator = twidth ? ", " : ",";
20550276Speter	trailer = "\n\t";
20650276Speter	break;
20750276Speter
20850276Speter    case F_VARIABLE:
20950276Speter	bool_names = boolfnames;
21050276Speter	num_names = numfnames;
21150276Speter	str_names = strfnames;
21250276Speter	separator = twidth ? ", " : ",";
21350276Speter	trailer = "\n\t";
21450276Speter	break;
21550276Speter
21650276Speter    case F_TERMCAP:
21750276Speter    case F_TCONVERR:
21850276Speter	bool_names = boolcodes;
21950276Speter	num_names = numcodes;
22050276Speter	str_names = strcodes;
22150276Speter	separator = ":";
22250276Speter	trailer = "\\\n\t:";
22350276Speter	break;
22450276Speter    }
22550276Speter
22650276Speter    /* implement sort modes */
22762449Speter    switch (sortmode = sort) {
22850276Speter    case S_NOSORT:
22950276Speter	if (traceval)
23050276Speter	    (void) fprintf(stderr,
23198503Speter			   "%s: sorting by term structure order\n", _nc_progname);
23250276Speter	break;
23350276Speter
23450276Speter    case S_TERMINFO:
23550276Speter	if (traceval)
23650276Speter	    (void) fprintf(stderr,
23798503Speter			   "%s: sorting by terminfo name order\n", _nc_progname);
23850276Speter	bool_indirect = bool_terminfo_sort;
23950276Speter	num_indirect = num_terminfo_sort;
24050276Speter	str_indirect = str_terminfo_sort;
24150276Speter	break;
24250276Speter
24350276Speter    case S_VARIABLE:
24450276Speter	if (traceval)
24550276Speter	    (void) fprintf(stderr,
24698503Speter			   "%s: sorting by C variable order\n", _nc_progname);
24750276Speter	bool_indirect = bool_variable_sort;
24850276Speter	num_indirect = num_variable_sort;
24950276Speter	str_indirect = str_variable_sort;
25050276Speter	break;
25150276Speter
25250276Speter    case S_TERMCAP:
25350276Speter	if (traceval)
25450276Speter	    (void) fprintf(stderr,
25598503Speter			   "%s: sorting by termcap name order\n", _nc_progname);
25650276Speter	bool_indirect = bool_termcap_sort;
25750276Speter	num_indirect = num_termcap_sort;
25850276Speter	str_indirect = str_termcap_sort;
25950276Speter	break;
26050276Speter    }
26150276Speter
26250276Speter    if (traceval)
26350276Speter	(void) fprintf(stderr,
26498503Speter		       "%s: width = %d, tversion = %d, outform = %d\n",
26598503Speter		       _nc_progname, width, tversion, outform);
26650276Speter}
26750276Speter
26862449Speterstatic TERMTYPE *cur_type;
26950276Speter
27062449Speterstatic int
271166124Srafandump_predicate(PredType type, PredIdx idx)
27250276Speter/* predicate function to use for ordinary decompilation */
27350276Speter{
27462449Speter    switch (type) {
27562449Speter    case BOOLEAN:
27662449Speter	return (cur_type->Booleans[idx] == FALSE)
27762449Speter	    ? FAIL : cur_type->Booleans[idx];
27850276Speter
27962449Speter    case NUMBER:
28062449Speter	return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
28162449Speter	    ? FAIL : cur_type->Numbers[idx];
28250276Speter
28362449Speter    case STRING:
28462449Speter	return (cur_type->Strings[idx] != ABSENT_STRING)
28562449Speter	    ? (int) TRUE : FAIL;
28662449Speter    }
28750276Speter
28862449Speter    return (FALSE);		/* pacify compiler */
28950276Speter}
29050276Speter
291166124Srafanstatic void set_obsolete_termcaps(TERMTYPE *tp);
29250276Speter
29350276Speter/* is this the index of a function key string? */
29450276Speter#define FNKEY(i)	(((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268))
29550276Speter
296166124Srafan/*
297166124Srafan * If we configure with a different Caps file, the offsets into the arrays
298166124Srafan * will change.  So we use an address expression.
299166124Srafan */
300184989Srafan#define BOOL_IDX(name) (PredType) (&(name) - &(CUR Booleans[0]))
301184989Srafan#define NUM_IDX(name)  (PredType) (&(name) - &(CUR Numbers[0]))
302184989Srafan#define STR_IDX(name)  (PredType) (&(name) - &(CUR Strings[0]))
303166124Srafan
30462449Speterstatic bool
305166124Srafanversion_filter(PredType type, PredIdx idx)
30650276Speter/* filter out capabilities we may want to suppress */
30750276Speter{
30862449Speter    switch (tversion) {
30962449Speter    case V_ALLCAPS:		/* SVr4, XSI Curses */
31062449Speter	return (TRUE);
31150276Speter
31262449Speter    case V_SVR1:		/* System V Release 1, Ultrix */
31362449Speter	switch (type) {
31450276Speter	case BOOLEAN:
315166124Srafan	    return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
31650276Speter	case NUMBER:
317166124Srafan	    return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
31850276Speter	case STRING:
319166124Srafan	    return ((idx <= STR_IDX(prtr_non)) ? TRUE : FALSE);
32050276Speter	}
32150276Speter	break;
32250276Speter
32350276Speter    case V_HPUX:		/* Hewlett-Packard */
32462449Speter	switch (type) {
32550276Speter	case BOOLEAN:
326166124Srafan	    return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
32750276Speter	case NUMBER:
328166124Srafan	    return ((idx <= NUM_IDX(label_width)) ? TRUE : FALSE);
32950276Speter	case STRING:
330166124Srafan	    if (idx <= STR_IDX(prtr_non))
33162449Speter		return (TRUE);
33250276Speter	    else if (FNKEY(idx))	/* function keys */
33362449Speter		return (TRUE);
334166124Srafan	    else if (idx == STR_IDX(plab_norm)
335166124Srafan		     || idx == STR_IDX(label_on)
336166124Srafan		     || idx == STR_IDX(label_off))
33762449Speter		return (TRUE);
33850276Speter	    else
33962449Speter		return (FALSE);
34050276Speter	}
34150276Speter	break;
34250276Speter
34350276Speter    case V_AIX:		/* AIX */
34462449Speter	switch (type) {
34550276Speter	case BOOLEAN:
346166124Srafan	    return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
34750276Speter	case NUMBER:
348166124Srafan	    return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
34950276Speter	case STRING:
350166124Srafan	    if (idx <= STR_IDX(prtr_non))
35162449Speter		return (TRUE);
35250276Speter	    else if (FNKEY(idx))	/* function keys */
35362449Speter		return (TRUE);
35450276Speter	    else
35562449Speter		return (FALSE);
35650276Speter	}
35750276Speter	break;
35850276Speter
359184989Srafan#define is_termcap(type) (OkIndex(idx, type##_from_termcap) && \
360174993Srafan			  type##_from_termcap[idx])
361174993Srafan
36250276Speter    case V_BSD:		/* BSD */
36362449Speter	switch (type) {
36450276Speter	case BOOLEAN:
365174993Srafan	    return is_termcap(bool);
36650276Speter	case NUMBER:
367174993Srafan	    return is_termcap(num);
36850276Speter	case STRING:
369174993Srafan	    return is_termcap(str);
37050276Speter	}
37150276Speter	break;
37250276Speter    }
37350276Speter
37462449Speter    return (FALSE);		/* pacify the compiler */
37550276Speter}
37650276Speter
37762449Speterstatic void
378166124Srafantrim_trailing(void)
379166124Srafan{
380166124Srafan    while (outbuf.used > 0 && outbuf.text[outbuf.used - 1] == ' ')
381166124Srafan	outbuf.text[--outbuf.used] = '\0';
382166124Srafan}
383166124Srafan
384166124Srafanstatic void
38562449Speterforce_wrap(void)
38650276Speter{
38762449Speter    oldcol = column;
388166124Srafan    trim_trailing();
38962449Speter    strcpy_DYN(&outbuf, trailer);
39062449Speter    column = INDENT;
39150276Speter}
39250276Speter
39362449Speterstatic void
39462449Speterwrap_concat(const char *src)
39550276Speter{
396184989Srafan    unsigned need = strlen(src);
397184989Srafan    unsigned want = strlen(separator) + need;
39850276Speter
39962449Speter    if (column > INDENT
400184989Srafan	&& column + (int) want > width) {
40162449Speter	force_wrap();
40262449Speter    }
40362449Speter    strcpy_DYN(&outbuf, src);
40462449Speter    strcpy_DYN(&outbuf, separator);
405184989Srafan    column += (int) need;
40650276Speter}
40750276Speter
40850276Speter#define IGNORE_SEP_TRAIL(first,last,sep_trail) \
40950276Speter	if ((size_t)(last - first) > sizeof(sep_trail)-1 \
41050276Speter	 && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
411184989Srafan		first += sizeof(sep_trail)-2
41250276Speter
41350276Speter/* Returns the nominal length of the buffer assuming it is termcap format,
41450276Speter * i.e., the continuation sequence is treated as a single character ":".
41550276Speter *
41650276Speter * There are several implementations of termcap which read the text into a
41750276Speter * fixed-size buffer.  Generally they strip the newlines from the text, but may
41850276Speter * not do it until after the buffer is read.  Also, "tc=" resolution may be
41950276Speter * expanded in the same buffer.  This function is useful for measuring the size
42050276Speter * of the best fixed-buffer implementation; the worst case may be much worse.
42150276Speter */
42250276Speter#ifdef TEST_TERMCAP_LENGTH
42362449Speterstatic int
42462449Spetertermcap_length(const char *src)
42550276Speter{
42662449Speter    static const char pattern[] = ":\\\n\t:";
42750276Speter
42862449Speter    int len = 0;
42962449Speter    const char *const t = src + strlen(src);
43050276Speter
43162449Speter    while (*src != '\0') {
43262449Speter	IGNORE_SEP_TRAIL(src, t, pattern);
43362449Speter	src++;
43462449Speter	len++;
43562449Speter    }
43662449Speter    return len;
43750276Speter}
43850276Speter#else
43950276Speter#define termcap_length(src) strlen(src)
44050276Speter#endif
44150276Speter
442166124Srafanstatic void
443166124Srafanindent_DYN(DYNBUF * buffer, int level)
444166124Srafan{
445166124Srafan    int n;
446166124Srafan
447166124Srafan    for (n = 0; n < level; n++)
448166124Srafan	strncpy_DYN(buffer, "\t", 1);
449166124Srafan}
450166124Srafan
451166124Srafanstatic bool
452166124Srafanhas_params(const char *src)
453166124Srafan{
454166124Srafan    bool result = FALSE;
455184989Srafan    int len = (int) strlen(src);
456166124Srafan    int n;
457166124Srafan    bool ifthen = FALSE;
458166124Srafan    bool params = FALSE;
459166124Srafan
460166124Srafan    for (n = 0; n < len - 1; ++n) {
461166124Srafan	if (!strncmp(src + n, "%p", 2)) {
462166124Srafan	    params = TRUE;
463166124Srafan	} else if (!strncmp(src + n, "%;", 2)) {
464166124Srafan	    ifthen = TRUE;
465166124Srafan	    result = params;
466166124Srafan	    break;
467166124Srafan	}
468166124Srafan    }
469166124Srafan    if (!ifthen) {
470166124Srafan	result = ((len > 50) && params);
471166124Srafan    }
472166124Srafan    return result;
473166124Srafan}
474166124Srafan
47562449Speterstatic char *
47662449Speterfmt_complex(char *src, int level)
47750276Speter{
478166124Srafan    bool percent = FALSE;
479166124Srafan    bool params = has_params(src);
48050276Speter
48162449Speter    while (*src != '\0') {
48262449Speter	switch (*src) {
48362449Speter	case '\\':
484166124Srafan	    percent = FALSE;
48562449Speter	    strncpy_DYN(&tmpbuf, src++, 1);
48662449Speter	    break;
48762449Speter	case '%':
488166124Srafan	    percent = TRUE;
48962449Speter	    break;
49062449Speter	case '?':		/* "if" */
49162449Speter	case 't':		/* "then" */
49262449Speter	case 'e':		/* "else" */
49362449Speter	    if (percent) {
494166124Srafan		percent = FALSE;
49562449Speter		tmpbuf.text[tmpbuf.used - 1] = '\n';
496166124Srafan		/* treat a "%e" as else-if, on the same level */
497166124Srafan		if (*src == 'e') {
498166124Srafan		    indent_DYN(&tmpbuf, level);
49962449Speter		    strncpy_DYN(&tmpbuf, "%", 1);
500166124Srafan		    strncpy_DYN(&tmpbuf, src, 1);
501166124Srafan		    src++;
502166124Srafan		    params = has_params(src);
503166124Srafan		    if (!params && *src != '\0' && *src != '%') {
504166124Srafan			strncpy_DYN(&tmpbuf, "\n", 1);
505166124Srafan			indent_DYN(&tmpbuf, level + 1);
506166124Srafan		    }
50762449Speter		} else {
508166124Srafan		    indent_DYN(&tmpbuf, level + 1);
50962449Speter		    strncpy_DYN(&tmpbuf, "%", 1);
51062449Speter		    strncpy_DYN(&tmpbuf, src, 1);
51162449Speter		    if (*src++ == '?') {
51262449Speter			src = fmt_complex(src, level + 1);
513166124Srafan			if (*src != '\0' && *src != '%') {
514166124Srafan			    strncpy_DYN(&tmpbuf, "\n", 1);
515166124Srafan			    indent_DYN(&tmpbuf, level + 1);
516166124Srafan			}
51762449Speter		    } else if (level == 1) {
51862449Speter			_nc_warning("%%%c without %%?", *src);
51962449Speter		    }
52050276Speter		}
52162449Speter		continue;
52262449Speter	    }
52362449Speter	    break;
52462449Speter	case ';':		/* "endif" */
52562449Speter	    if (percent) {
526166124Srafan		percent = FALSE;
52762449Speter		if (level > 1) {
52862449Speter		    tmpbuf.text[tmpbuf.used - 1] = '\n';
529166124Srafan		    indent_DYN(&tmpbuf, level);
53062449Speter		    strncpy_DYN(&tmpbuf, "%", 1);
53162449Speter		    strncpy_DYN(&tmpbuf, src++, 1);
53262449Speter		    return src;
53362449Speter		}
53462449Speter		_nc_warning("%%; without %%?");
53562449Speter	    }
53662449Speter	    break;
53762449Speter	case 'p':
53862449Speter	    if (percent && params) {
53962449Speter		tmpbuf.text[tmpbuf.used - 1] = '\n';
540166124Srafan		indent_DYN(&tmpbuf, level + 1);
54162449Speter		strncpy_DYN(&tmpbuf, "%", 1);
54262449Speter	    }
543166124Srafan	    params = FALSE;
544166124Srafan	    percent = FALSE;
54562449Speter	    break;
546178866Srafan	case ' ':
547178866Srafan	    strncpy_DYN(&tmpbuf, "\\s", 2);
548178866Srafan	    ++src;
549178866Srafan	    continue;
55062449Speter	default:
551166124Srafan	    percent = FALSE;
55262449Speter	    break;
55350276Speter	}
55462449Speter	strncpy_DYN(&tmpbuf, src++, 1);
55562449Speter    }
55662449Speter    return src;
55750276Speter}
55850276Speter
559166124Srafan#define SAME_CAP(n,cap) (&tterm->Strings[n] == &cap)
560184989Srafan#define EXTRA_CAP 20
561166124Srafan
56262449Speterint
563166124Srafanfmt_entry(TERMTYPE *tterm,
564166124Srafan	  PredFunc pred,
565166124Srafan	  bool content_only,
56698503Speter	  bool suppress_untranslatable,
56798503Speter	  bool infodump,
56898503Speter	  int numbers)
56950276Speter{
570166124Srafan    PredIdx i, j;
571184989Srafan    char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
572166124Srafan    char *capability;
57362449Speter    NCURSES_CONST char *name;
57462449Speter    int predval, len;
575166124Srafan    PredIdx num_bools = 0;
576166124Srafan    PredIdx num_values = 0;
577166124Srafan    PredIdx num_strings = 0;
57862449Speter    bool outcount = 0;
57950276Speter
58050276Speter#define WRAP_CONCAT	\
58150276Speter	wrap_concat(buffer); \
58250276Speter	outcount = TRUE
58350276Speter
58450276Speter    len = 12;			/* terminfo file-header */
58550276Speter
58650276Speter    if (pred == 0) {
58750276Speter	cur_type = tterm;
58850276Speter	pred = dump_predicate;
58950276Speter    }
59050276Speter
59162449Speter    strcpy_DYN(&outbuf, 0);
592166124Srafan    if (content_only) {
593166124Srafan	column = INDENT;	/* FIXME: workaround to prevent empty lines */
594166124Srafan    } else {
595166124Srafan	strcpy_DYN(&outbuf, tterm->term_names);
596166124Srafan	strcpy_DYN(&outbuf, separator);
597184989Srafan	column = (int) outbuf.used;
598166124Srafan	force_wrap();
599166124Srafan    }
60050276Speter
60162449Speter    for_each_boolean(j, tterm) {
60250276Speter	i = BoolIndirect(j);
60362449Speter	name = ExtBoolname(tterm, i, bool_names);
604184989Srafan	assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
60550276Speter
60650276Speter	if (!version_filter(BOOLEAN, i))
60750276Speter	    continue;
60862449Speter	else if (isObsolete(outform, name))
60950276Speter	    continue;
61050276Speter
61150276Speter	predval = pred(BOOLEAN, i);
61250276Speter	if (predval != FAIL) {
61350276Speter	    (void) strcpy(buffer, name);
61450276Speter	    if (predval <= 0)
61550276Speter		(void) strcat(buffer, "@");
61650276Speter	    else if (i + 1 > num_bools)
61750276Speter		num_bools = i + 1;
61850276Speter	    WRAP_CONCAT;
61950276Speter	}
62050276Speter    }
62150276Speter
62250276Speter    if (column != INDENT)
62350276Speter	force_wrap();
62450276Speter
62562449Speter    for_each_number(j, tterm) {
62650276Speter	i = NumIndirect(j);
62762449Speter	name = ExtNumname(tterm, i, num_names);
628184989Srafan	assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
62950276Speter
63050276Speter	if (!version_filter(NUMBER, i))
63150276Speter	    continue;
63262449Speter	else if (isObsolete(outform, name))
63350276Speter	    continue;
63450276Speter
63550276Speter	predval = pred(NUMBER, i);
63650276Speter	if (predval != FAIL) {
63750276Speter	    if (tterm->Numbers[i] < 0) {
63850276Speter		sprintf(buffer, "%s@", name);
63950276Speter	    } else {
64050276Speter		sprintf(buffer, "%s#%d", name, tterm->Numbers[i]);
64150276Speter		if (i + 1 > num_values)
64250276Speter		    num_values = i + 1;
64350276Speter	    }
64450276Speter	    WRAP_CONCAT;
64550276Speter	}
64650276Speter    }
64750276Speter
64850276Speter    if (column != INDENT)
64950276Speter	force_wrap();
65050276Speter
651184989Srafan    len += (int) (num_bools
652184989Srafan		  + num_values * 2
653184989Srafan		  + strlen(tterm->term_names) + 1);
65450276Speter    if (len & 1)
65562449Speter	len++;
65650276Speter
65762449Speter#undef CUR
65862449Speter#define CUR tterm->
65962449Speter    if (outform == F_TERMCAP) {
66062449Speter	if (termcap_reset != ABSENT_STRING) {
66162449Speter	    if (init_3string != ABSENT_STRING
66262449Speter		&& !strcmp(init_3string, termcap_reset))
66362449Speter		DISCARD(init_3string);
66462449Speter
66562449Speter	    if (reset_2string != ABSENT_STRING
66662449Speter		&& !strcmp(reset_2string, termcap_reset))
66762449Speter		DISCARD(reset_2string);
66862449Speter	}
66962449Speter    }
67062449Speter
67150276Speter    for_each_string(j, tterm) {
67250276Speter	i = StrIndirect(j);
67362449Speter	name = ExtStrname(tterm, i, str_names);
674184989Srafan	assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
675184989Srafan
676166124Srafan	capability = tterm->Strings[i];
67750276Speter
67850276Speter	if (!version_filter(STRING, i))
67950276Speter	    continue;
68062449Speter	else if (isObsolete(outform, name))
68150276Speter	    continue;
68250276Speter
683166124Srafan#if NCURSES_XNAMES
68450276Speter	/*
685166124Srafan	 * Extended names can be longer than 2 characters, but termcap programs
686166124Srafan	 * cannot read those (filter them out).
68750276Speter	 */
688166124Srafan	if (outform == F_TERMCAP && (strlen(name) > 2))
689166124Srafan	    continue;
690166124Srafan#endif
691166124Srafan
69262449Speter	if (outform == F_TERMCAP) {
693166124Srafan	    /*
694166124Srafan	     * Some older versions of vi want rmir/smir to be defined
695166124Srafan	     * for ich/ich1 to work.  If they're not defined, force
696166124Srafan	     * them to be output as defined and empty.
697166124Srafan	     */
698166124Srafan	    if (PRESENT(insert_character) || PRESENT(parm_ich)) {
699166124Srafan		if (SAME_CAP(i, enter_insert_mode)
70062449Speter		    && enter_insert_mode == ABSENT_STRING) {
70150276Speter		    (void) strcpy(buffer, "im=");
70262449Speter		    WRAP_CONCAT;
70362449Speter		    continue;
70450276Speter		}
70550276Speter
706166124Srafan		if (SAME_CAP(i, exit_insert_mode)
70762449Speter		    && exit_insert_mode == ABSENT_STRING) {
70850276Speter		    (void) strcpy(buffer, "ei=");
70962449Speter		    WRAP_CONCAT;
71062449Speter		    continue;
71150276Speter		}
71250276Speter	    }
713166124Srafan	    /*
714166124Srafan	     * termcap applications such as screen will be confused if sgr0
715166124Srafan	     * is translated to a string containing rmacs.  Filter that out.
716166124Srafan	     */
717166124Srafan	    if (PRESENT(exit_attribute_mode)) {
718166124Srafan		if (SAME_CAP(i, exit_attribute_mode)) {
719166124Srafan		    char *trimmed_sgr0;
720166124Srafan		    char *my_sgr = set_attributes;
721166124Srafan
722166124Srafan		    set_attributes = save_sgr;
723166124Srafan
724166124Srafan		    trimmed_sgr0 = _nc_trim_sgr0(tterm);
725166124Srafan		    if (strcmp(capability, trimmed_sgr0))
726166124Srafan			capability = trimmed_sgr0;
727166124Srafan
728166124Srafan		    set_attributes = my_sgr;
729166124Srafan		}
730166124Srafan	    }
73150276Speter	}
73250276Speter
73350276Speter	predval = pred(STRING, i);
73450276Speter	buffer[0] = '\0';
73562449Speter
73650276Speter	if (predval != FAIL) {
737166124Srafan	    if (capability != ABSENT_STRING
73862449Speter		&& i + 1 > num_strings)
73950276Speter		num_strings = i + 1;
74062449Speter
741166124Srafan	    if (!VALID_STRING(capability)) {
74250276Speter		sprintf(buffer, "%s@", name);
74362449Speter		WRAP_CONCAT;
74462449Speter	    } else if (outform == F_TERMCAP || outform == F_TCONVERR) {
74598503Speter		int params = ((i < (int) SIZEOF(parametrized))
74698503Speter			      ? parametrized[i]
74798503Speter			      : 0);
748166124Srafan		char *srccap = _nc_tic_expand(capability, TRUE, numbers);
74966963Speter		char *cv = _nc_infotocap(name, srccap, params);
75050276Speter
75162449Speter		if (cv == 0) {
75262449Speter		    if (outform == F_TCONVERR) {
75362449Speter			sprintf(buffer, "%s=!!! %s WILL NOT CONVERT !!!",
75498503Speter				name, srccap);
75562449Speter		    } else if (suppress_untranslatable) {
75650276Speter			continue;
75762449Speter		    } else {
75862449Speter			char *s = srccap, *d = buffer;
75962449Speter			sprintf(d, "..%s=", name);
76062449Speter			d += strlen(d);
76162449Speter			while ((*d = *s++) != 0) {
76262449Speter			    if (*d == ':') {
76362449Speter				*d++ = '\\';
76462449Speter				*d = ':';
76562449Speter			    } else if (*d == '\\') {
76662449Speter				*++d = *s++;
76762449Speter			    }
76862449Speter			    d++;
76962449Speter			}
77062449Speter		    }
77162449Speter		} else {
77262449Speter		    sprintf(buffer, "%s=%s", name, cv);
77350276Speter		}
774184989Srafan		len += (int) strlen(capability) + 1;
77562449Speter		WRAP_CONCAT;
77662449Speter	    } else {
777166124Srafan		char *src = _nc_tic_expand(capability,
77898503Speter					   outform == F_TERMINFO, numbers);
77962449Speter
78062449Speter		strcpy_DYN(&tmpbuf, 0);
78162449Speter		strcpy_DYN(&tmpbuf, name);
78262449Speter		strcpy_DYN(&tmpbuf, "=");
78362449Speter		if (pretty
78462449Speter		    && (outform == F_TERMINFO
78562449Speter			|| outform == F_VARIABLE)) {
78662449Speter		    fmt_complex(src, 1);
78762449Speter		} else {
78862449Speter		    strcpy_DYN(&tmpbuf, src);
78962449Speter		}
790184989Srafan		len += (int) strlen(capability) + 1;
79162449Speter		wrap_concat(tmpbuf.text);
79262449Speter		outcount = TRUE;
79350276Speter	    }
79450276Speter	}
795166124Srafan	/* e.g., trimmed_sgr0 */
796166124Srafan	if (capability != tterm->Strings[i])
797166124Srafan	    free(capability);
79850276Speter    }
799184989Srafan    len += (int) (num_strings * 2);
80050276Speter
80150276Speter    /*
80250276Speter     * This piece of code should be an effective inverse of the functions
803166124Srafan     * postprocess_terminfo() and postprocess_terminfo() in parse_entry.c.
80450276Speter     * Much more work should be done on this to support dumping termcaps.
80550276Speter     */
80662449Speter    if (tversion == V_HPUX) {
807174993Srafan	if (VALID_STRING(memory_lock)) {
80850276Speter	    (void) sprintf(buffer, "meml=%s", memory_lock);
80950276Speter	    WRAP_CONCAT;
81050276Speter	}
811174993Srafan	if (VALID_STRING(memory_unlock)) {
81250276Speter	    (void) sprintf(buffer, "memu=%s", memory_unlock);
81350276Speter	    WRAP_CONCAT;
81450276Speter	}
81562449Speter    } else if (tversion == V_AIX) {
81662449Speter	if (VALID_STRING(acs_chars)) {
81762449Speter	    bool box_ok = TRUE;
81862449Speter	    const char *acstrans = "lqkxjmwuvtn";
81962449Speter	    const char *cp;
82062449Speter	    char *tp, *sp, boxchars[11];
82150276Speter
82250276Speter	    tp = boxchars;
82362449Speter	    for (cp = acstrans; *cp; cp++) {
82450276Speter		sp = strchr(acs_chars, *cp);
82550276Speter		if (sp)
82650276Speter		    *tp++ = sp[1];
82762449Speter		else {
82850276Speter		    box_ok = FALSE;
82950276Speter		    break;
83050276Speter		}
83150276Speter	    }
83250276Speter	    tp[0] = '\0';
83350276Speter
83462449Speter	    if (box_ok) {
83550276Speter		(void) strcpy(buffer, "box1=");
83662449Speter		(void) strcat(buffer, _nc_tic_expand(boxchars,
83798503Speter						     outform == F_TERMINFO, numbers));
83850276Speter		WRAP_CONCAT;
83950276Speter	    }
84050276Speter	}
84150276Speter    }
84250276Speter
84350276Speter    /*
84450276Speter     * kludge: trim off trailer to avoid an extra blank line
84550276Speter     * in infocmp -u output when there are no string differences
84650276Speter     */
84762449Speter    if (outcount) {
84862449Speter	bool trimmed = FALSE;
84962449Speter	j = outbuf.used;
85050276Speter	if (j >= 2
85162449Speter	    && outbuf.text[j - 1] == '\t'
85262449Speter	    && outbuf.text[j - 2] == '\n') {
85362449Speter	    outbuf.used -= 2;
85462449Speter	    trimmed = TRUE;
85550276Speter	} else if (j >= 4
85698503Speter		   && outbuf.text[j - 1] == ':'
85798503Speter		   && outbuf.text[j - 2] == '\t'
85898503Speter		   && outbuf.text[j - 3] == '\n'
85998503Speter		   && outbuf.text[j - 4] == '\\') {
86062449Speter	    outbuf.used -= 4;
86162449Speter	    trimmed = TRUE;
86250276Speter	}
86362449Speter	if (trimmed) {
86462449Speter	    outbuf.text[outbuf.used] = '\0';
86562449Speter	    column = oldcol;
866166124Srafan	    strcpy_DYN(&outbuf, " ");
86762449Speter	}
86850276Speter    }
86950276Speter#if 0
87050276Speter    fprintf(stderr, "num_bools = %d\n", num_bools);
87150276Speter    fprintf(stderr, "num_values = %d\n", num_values);
87250276Speter    fprintf(stderr, "num_strings = %d\n", num_strings);
87350276Speter    fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
87498503Speter	    tterm->term_names, len, outbuf.used, outbuf.text);
87550276Speter#endif
87650276Speter    /*
87750276Speter     * Here's where we use infodump to trigger a more stringent length check
87850276Speter     * for termcap-translation purposes.
87950276Speter     * Return the length of the raw entry, without tc= expansions,
88050276Speter     * It gives an idea of which entries are deadly to even *scan past*,
88150276Speter     * as opposed to *use*.
88250276Speter     */
88376726Speter    return (infodump ? len : (int) termcap_length(outbuf.text));
88450276Speter}
88550276Speter
88698503Speterstatic bool
887166124Srafankill_string(TERMTYPE *tterm, char *cap)
88898503Speter{
889184989Srafan    unsigned n;
890166124Srafan    for (n = 0; n < NUM_STRINGS(tterm); ++n) {
89198503Speter	if (cap == tterm->Strings[n]) {
89298503Speter	    tterm->Strings[n] = ABSENT_STRING;
89398503Speter	    return TRUE;
89498503Speter	}
89598503Speter    }
89698503Speter    return FALSE;
89798503Speter}
89898503Speter
89998503Speterstatic char *
900166124Srafanfind_string(TERMTYPE *tterm, char *name)
90198503Speter{
902166124Srafan    PredIdx n;
903166124Srafan    for (n = 0; n < NUM_STRINGS(tterm); ++n) {
90498503Speter	if (version_filter(STRING, n)
90598503Speter	    && !strcmp(name, strnames[n])) {
90698503Speter	    char *cap = tterm->Strings[n];
90798503Speter	    if (VALID_STRING(cap)) {
90898503Speter		return cap;
90998503Speter	    }
91098503Speter	    break;
91198503Speter	}
91298503Speter    }
91398503Speter    return ABSENT_STRING;
91498503Speter}
91598503Speter
91698503Speter/*
91798503Speter * This is used to remove function-key labels from a termcap entry to
91898503Speter * make it smaller.
91998503Speter */
92098503Speterstatic int
921166124Srafankill_labels(TERMTYPE *tterm, int target)
92298503Speter{
92398503Speter    int n;
92498503Speter    int result = 0;
92598503Speter    char *cap;
92698503Speter    char name[10];
92798503Speter
92898503Speter    for (n = 0; n <= 10; ++n) {
92998503Speter	sprintf(name, "lf%d", n);
93098503Speter	if ((cap = find_string(tterm, name)) != ABSENT_STRING
93198503Speter	    && kill_string(tterm, cap)) {
932184989Srafan	    target -= (int) (strlen(cap) + 5);
93398503Speter	    ++result;
93498503Speter	    if (target < 0)
93598503Speter		break;
93698503Speter	}
93798503Speter    }
93898503Speter    return result;
93998503Speter}
94098503Speter
94198503Speter/*
94298503Speter * This is used to remove function-key definitions from a termcap entry to
94398503Speter * make it smaller.
94498503Speter */
94598503Speterstatic int
946166124Srafankill_fkeys(TERMTYPE *tterm, int target)
94798503Speter{
94898503Speter    int n;
94998503Speter    int result = 0;
95098503Speter    char *cap;
95198503Speter    char name[10];
95298503Speter
95398503Speter    for (n = 60; n >= 0; --n) {
95498503Speter	sprintf(name, "kf%d", n);
95598503Speter	if ((cap = find_string(tterm, name)) != ABSENT_STRING
95698503Speter	    && kill_string(tterm, cap)) {
957184989Srafan	    target -= (int) (strlen(cap) + 5);
95898503Speter	    ++result;
95998503Speter	    if (target < 0)
96098503Speter		break;
96198503Speter	}
96298503Speter    }
96398503Speter    return result;
96498503Speter}
96598503Speter
966166124Srafan/*
967166124Srafan * Check if the given acsc string is a 1-1 mapping, i.e., just-like-vt100.
968166124Srafan * Also, since this is for termcap, we only care about the line-drawing map.
969166124Srafan */
970166124Srafan#define isLine(c) (strchr("lmkjtuvwqxn", c) != 0)
971166124Srafan
972166124Srafanstatic bool
973166124Srafanone_one_mapping(const char *mapping)
974166124Srafan{
975166124Srafan    bool result = TRUE;
976166124Srafan
977166124Srafan    if (mapping != ABSENT_STRING) {
978166124Srafan	int n = 0;
979166124Srafan	while (mapping[n] != '\0') {
980166124Srafan	    if (isLine(mapping[n]) &&
981166124Srafan		mapping[n] != mapping[n + 1]) {
982166124Srafan		result = FALSE;
983166124Srafan		break;
984166124Srafan	    }
985166124Srafan	    n += 2;
986166124Srafan	}
987166124Srafan    }
988166124Srafan    return result;
989166124Srafan}
990166124Srafan
991166124Srafan#define FMT_ENTRY() \
992166124Srafan		fmt_entry(tterm, pred, \
993166124Srafan			0, \
994166124Srafan			suppress_untranslatable, \
995166124Srafan			infodump, numbers)
996166124Srafan
997166124Srafan#define SHOW_WHY PRINTF
998166124Srafan
999166124Srafanstatic bool
1000166124Srafanpurged_acs(TERMTYPE *tterm)
1001166124Srafan{
1002166124Srafan    bool result = FALSE;
1003166124Srafan
1004166124Srafan    if (VALID_STRING(acs_chars)) {
1005166124Srafan	if (!one_one_mapping(acs_chars)) {
1006166124Srafan	    enter_alt_charset_mode = ABSENT_STRING;
1007166124Srafan	    exit_alt_charset_mode = ABSENT_STRING;
1008166124Srafan	    SHOW_WHY("# (rmacs/smacs removed for consistency)\n");
1009166124Srafan	}
1010166124Srafan	result = TRUE;
1011166124Srafan    }
1012166124Srafan    return result;
1013166124Srafan}
1014166124Srafan
1015166124Srafan/*
1016166124Srafan * Dump a single entry.
1017166124Srafan */
1018166124Srafanvoid
1019166124Srafandump_entry(TERMTYPE *tterm,
1020166124Srafan	   bool suppress_untranslatable,
102198503Speter	   bool limited,
102298503Speter	   int numbers,
1023166124Srafan	   PredFunc pred)
102450276Speter{
1025166124Srafan    TERMTYPE save_tterm;
102662449Speter    int len, critlen;
102762449Speter    const char *legend;
102862449Speter    bool infodump;
102950276Speter
103062449Speter    if (outform == F_TERMCAP || outform == F_TCONVERR) {
103150276Speter	critlen = MAX_TERMCAP_LENGTH;
103250276Speter	legend = "older termcap";
103350276Speter	infodump = FALSE;
103450276Speter	set_obsolete_termcaps(tterm);
103562449Speter    } else {
103650276Speter	critlen = MAX_TERMINFO_LENGTH;
103750276Speter	legend = "terminfo";
103850276Speter	infodump = TRUE;
103950276Speter    }
104050276Speter
1041166124Srafan    save_sgr = set_attributes;
1042166124Srafan
1043166124Srafan    if (((len = FMT_ENTRY()) > critlen)
104462449Speter	&& limited) {
1045166124Srafan
1046166124Srafan	save_tterm = *tterm;
1047166124Srafan	if (!suppress_untranslatable) {
1048166124Srafan	    SHOW_WHY("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
1049166124Srafan		     critlen);
1050166124Srafan	    suppress_untranslatable = TRUE;
1051166124Srafan	}
1052166124Srafan	if ((len = FMT_ENTRY()) > critlen) {
105350276Speter	    /*
105450276Speter	     * We pick on sgr because it's a nice long string capability that
105562449Speter	     * is really just an optimization hack.  Another good candidate is
105662449Speter	     * acsc since it is both long and unused by BSD termcap.
105750276Speter	     */
1058166124Srafan	    bool changed = FALSE;
1059166124Srafan
1060166124Srafan#if NCURSES_XNAMES
1061166124Srafan	    /*
1062166124Srafan	     * Extended names are most likely function-key definitions.  Drop
1063166124Srafan	     * those first.
1064166124Srafan	     */
1065184989Srafan	    unsigned n;
1066166124Srafan	    for (n = STRCOUNT; n < NUM_STRINGS(tterm); n++) {
1067166124Srafan		const char *name = ExtStrname(tterm, n, strnames);
1068166124Srafan
1069166124Srafan		if (VALID_STRING(tterm->Strings[n])) {
1070166124Srafan		    set_attributes = ABSENT_STRING;
1071166124Srafan		    /* we remove long names anyway - only report the short */
1072166124Srafan		    if (strlen(name) <= 2) {
1073166124Srafan			SHOW_WHY("# (%s removed to fit entry within %d bytes)\n",
1074166124Srafan				 name,
1075166124Srafan				 critlen);
1076166124Srafan		    }
1077166124Srafan		    changed = TRUE;
1078166124Srafan		    if ((len = FMT_ENTRY()) <= critlen)
1079166124Srafan			break;
1080166124Srafan		}
108162449Speter	    }
1082166124Srafan#endif
1083166124Srafan	    if (VALID_STRING(set_attributes)) {
1084166124Srafan		set_attributes = ABSENT_STRING;
1085166124Srafan		SHOW_WHY("# (sgr removed to fit entry within %d bytes)\n",
1086166124Srafan			 critlen);
1087166124Srafan		changed = TRUE;
1088166124Srafan	    }
1089166124Srafan	    if (!changed || ((len = FMT_ENTRY()) > critlen)) {
1090166124Srafan		if (purged_acs(tterm)) {
1091166124Srafan		    acs_chars = ABSENT_STRING;
1092166124Srafan		    SHOW_WHY("# (acsc removed to fit entry within %d bytes)\n",
1093166124Srafan			     critlen);
1094166124Srafan		    changed = TRUE;
1095166124Srafan		}
1096166124Srafan	    }
1097166124Srafan	    if (!changed || ((len = FMT_ENTRY()) > critlen)) {
109850276Speter		int oldversion = tversion;
109950276Speter
110050276Speter		tversion = V_BSD;
1101166124Srafan		SHOW_WHY("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
1102166124Srafan			 critlen);
110350276Speter
1104166124Srafan		len = FMT_ENTRY();
110598503Speter		if (len > critlen
110698503Speter		    && kill_labels(tterm, len - critlen)) {
1107166124Srafan		    SHOW_WHY("# (some labels capabilities suppressed to fit entry within %d bytes)\n",
1108166124Srafan			     critlen);
1109166124Srafan		    len = FMT_ENTRY();
111098503Speter		}
111198503Speter		if (len > critlen
111298503Speter		    && kill_fkeys(tterm, len - critlen)) {
1113166124Srafan		    SHOW_WHY("# (some function-key capabilities suppressed to fit entry within %d bytes)\n",
1114166124Srafan			     critlen);
1115166124Srafan		    len = FMT_ENTRY();
111698503Speter		}
111798503Speter		if (len > critlen) {
111850276Speter		    (void) fprintf(stderr,
111998503Speter				   "warning: %s entry is %d bytes long\n",
112098503Speter				   _nc_first_name(tterm->term_names),
112198503Speter				   len);
1122166124Srafan		    SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
1123166124Srafan			     len, legend);
112450276Speter		}
112550276Speter		tversion = oldversion;
112650276Speter	    }
1127166124Srafan	    set_attributes = save_sgr;
1128166124Srafan	    *tterm = save_tterm;
112950276Speter	}
1130166124Srafan    } else if (!version_filter(STRING, STR_IDX(acs_chars))) {
1131166124Srafan	save_tterm = *tterm;
1132166124Srafan	if (purged_acs(tterm)) {
1133166124Srafan	    len = FMT_ENTRY();
1134166124Srafan	}
1135166124Srafan	*tterm = save_tterm;
113650276Speter    }
113750276Speter}
113850276Speter
1139166124Srafanvoid
114062449Speterdump_uses(const char *name, bool infodump)
114150276Speter/* dump "use=" clauses in the appropriate format */
114250276Speter{
114350276Speter    char buffer[MAX_TERMINFO_LENGTH];
114450276Speter
1145166124Srafan    if (outform == F_TERMCAP || outform == F_TCONVERR)
1146166124Srafan	trim_trailing();
114762449Speter    (void) sprintf(buffer, "%s%s", infodump ? "use=" : "tc=", name);
114850276Speter    wrap_concat(buffer);
1149166124Srafan}
1150166124Srafan
1151166124Srafanint
1152166124Srafanshow_entry(void)
1153166124Srafan{
1154166124Srafan    trim_trailing();
115562449Speter    (void) fputs(outbuf.text, stdout);
1156166124Srafan    putchar('\n');
1157184989Srafan    return (int) outbuf.used;
115850276Speter}
115950276Speter
116062449Spetervoid
1161166124Srafancompare_entry(void (*hook) (PredType t, PredIdx i, const char *name),
1162166124Srafan	      TERMTYPE *tp GCC_UNUSED,
1163166124Srafan	      bool quiet)
116450276Speter/* compare two entries */
116550276Speter{
1166166124Srafan    PredIdx i, j;
116762449Speter    NCURSES_CONST char *name;
116850276Speter
116962449Speter    if (!quiet)
117062449Speter	fputs("    comparing booleans.\n", stdout);
117162449Speter    for_each_boolean(j, tp) {
117250276Speter	i = BoolIndirect(j);
117362449Speter	name = ExtBoolname(tp, i, bool_names);
117450276Speter
117562449Speter	if (isObsolete(outform, name))
117650276Speter	    continue;
117750276Speter
117862449Speter	(*hook) (CMP_BOOLEAN, i, name);
117950276Speter    }
118050276Speter
118162449Speter    if (!quiet)
118262449Speter	fputs("    comparing numbers.\n", stdout);
118362449Speter    for_each_number(j, tp) {
118450276Speter	i = NumIndirect(j);
118562449Speter	name = ExtNumname(tp, i, num_names);
118650276Speter
118762449Speter	if (isObsolete(outform, name))
118850276Speter	    continue;
118950276Speter
119062449Speter	(*hook) (CMP_NUMBER, i, name);
119150276Speter    }
119250276Speter
119362449Speter    if (!quiet)
119462449Speter	fputs("    comparing strings.\n", stdout);
119562449Speter    for_each_string(j, tp) {
119650276Speter	i = StrIndirect(j);
119762449Speter	name = ExtStrname(tp, i, str_names);
119850276Speter
119962449Speter	if (isObsolete(outform, name))
120050276Speter	    continue;
120150276Speter
120262449Speter	(*hook) (CMP_STRING, i, name);
120350276Speter    }
120462449Speter
120562449Speter    /* (void) fputs("    comparing use entries.\n", stdout); */
120662449Speter    (*hook) (CMP_USE, 0, "use");
120762449Speter
120850276Speter}
120950276Speter
121050276Speter#define NOTSET(s)	((s) == 0)
121150276Speter
121250276Speter/*
121350276Speter * This bit of legerdemain turns all the terminfo variable names into
121450276Speter * references to locations in the arrays Booleans, Numbers, and Strings ---
121550276Speter * precisely what's needed.
121650276Speter */
121750276Speter#undef CUR
121850276Speter#define CUR tp->
121950276Speter
122062449Speterstatic void
1221166124Srafanset_obsolete_termcaps(TERMTYPE *tp)
122250276Speter{
122350276Speter#include "capdefaults.c"
122450276Speter}
122550276Speter
122650276Speter/*
122750276Speter * Convert an alternate-character-set string to canonical form: sorted and
122850276Speter * unique.
122950276Speter */
123062449Spetervoid
1231166124Srafanrepair_acsc(TERMTYPE *tp)
123250276Speter{
123362449Speter    if (VALID_STRING(acs_chars)) {
123462449Speter	size_t n, m;
123562449Speter	char mapped[256];
123662449Speter	char extra = 0;
123762449Speter	unsigned source;
123862449Speter	unsigned target;
123962449Speter	bool fix_needed = FALSE;
124050276Speter
124162449Speter	for (n = 0, source = 0; acs_chars[n] != 0; n++) {
1242174993Srafan	    target = UChar(acs_chars[n]);
124362449Speter	    if (source >= target) {
124462449Speter		fix_needed = TRUE;
124562449Speter		break;
124662449Speter	    }
124762449Speter	    source = target;
124862449Speter	    if (acs_chars[n + 1])
124962449Speter		n++;
125062449Speter	}
125162449Speter	if (fix_needed) {
125262449Speter	    memset(mapped, 0, sizeof(mapped));
125362449Speter	    for (n = 0; acs_chars[n] != 0; n++) {
1254174993Srafan		source = UChar(acs_chars[n]);
125562449Speter		if ((target = (unsigned char) acs_chars[n + 1]) != 0) {
1256184989Srafan		    mapped[source] = (char) target;
125762449Speter		    n++;
125862449Speter		} else {
1259184989Srafan		    extra = (char) source;
126050276Speter		}
126150276Speter	    }
126262449Speter	    for (n = m = 0; n < sizeof(mapped); n++) {
126362449Speter		if (mapped[n]) {
1264184989Srafan		    acs_chars[m++] = (char) n;
126562449Speter		    acs_chars[m++] = mapped[n];
126650276Speter		}
126750276Speter	    }
126862449Speter	    if (extra)
126962449Speter		acs_chars[m++] = extra;		/* garbage in, garbage out */
127062449Speter	    acs_chars[m] = 0;
127150276Speter	}
127262449Speter    }
127350276Speter}
1274