15f4613f2SJohn Marino /****************************************************************************
2*32bb5217SDaniel Fojt  * Copyright 2018-2019,2020 Thomas E. Dickey                                *
3*32bb5217SDaniel Fojt  * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
45f4613f2SJohn Marino  *                                                                          *
55f4613f2SJohn Marino  * Permission is hereby granted, free of charge, to any person obtaining a  *
65f4613f2SJohn Marino  * copy of this software and associated documentation files (the            *
75f4613f2SJohn Marino  * "Software"), to deal in the Software without restriction, including      *
85f4613f2SJohn Marino  * without limitation the rights to use, copy, modify, merge, publish,      *
95f4613f2SJohn Marino  * distribute, distribute with modifications, sublicense, and/or sell       *
105f4613f2SJohn Marino  * copies of the Software, and to permit persons to whom the Software is    *
115f4613f2SJohn Marino  * furnished to do so, subject to the following conditions:                 *
125f4613f2SJohn Marino  *                                                                          *
135f4613f2SJohn Marino  * The above copyright notice and this permission notice shall be included  *
145f4613f2SJohn Marino  * in all copies or substantial portions of the Software.                   *
155f4613f2SJohn Marino  *                                                                          *
165f4613f2SJohn Marino  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
175f4613f2SJohn Marino  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
185f4613f2SJohn Marino  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
195f4613f2SJohn Marino  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
205f4613f2SJohn Marino  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
215f4613f2SJohn Marino  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
225f4613f2SJohn Marino  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
235f4613f2SJohn Marino  *                                                                          *
245f4613f2SJohn Marino  * Except as contained in this notice, the name(s) of the above copyright   *
255f4613f2SJohn Marino  * holders shall not be used in advertising or otherwise to promote the     *
265f4613f2SJohn Marino  * sale, use or other dealings in this Software without prior written       *
275f4613f2SJohn Marino  * authorization.                                                           *
285f4613f2SJohn Marino  ****************************************************************************/
295f4613f2SJohn Marino 
305f4613f2SJohn Marino /****************************************************************************
315f4613f2SJohn Marino  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
325f4613f2SJohn Marino  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
335f4613f2SJohn Marino  *     and: Thomas E. Dickey                        1996 on                 *
345f4613f2SJohn Marino  ****************************************************************************/
355f4613f2SJohn Marino 
365f4613f2SJohn Marino #define __INTERNAL_CAPS_VISIBLE
375f4613f2SJohn Marino #include <progs.priv.h>
385f4613f2SJohn Marino 
395f4613f2SJohn Marino #include "dump_entry.h"
405f4613f2SJohn Marino #include "termsort.c"		/* this C file is generated */
415f4613f2SJohn Marino #include <parametrized.h>	/* so is this */
425f4613f2SJohn Marino 
43*32bb5217SDaniel Fojt MODULE_ID("$Id: dump_entry.c,v 1.176 2020/02/02 23:34:34 tom Exp $")
445f4613f2SJohn Marino 
455f4613f2SJohn Marino #define DISCARD(string) string = ABSENT_STRING
465f4613f2SJohn Marino #define PRINTF (void) printf
47*32bb5217SDaniel Fojt #define WRAPPED 32
485f4613f2SJohn Marino 
495f4613f2SJohn Marino #define OkIndex(index,array) ((int)(index) >= 0 && (int)(index) < (int) SIZEOF(array))
50*32bb5217SDaniel Fojt #define TcOutput() (outform == F_TERMCAP || outform == F_TCONVERR)
515f4613f2SJohn Marino 
525f4613f2SJohn Marino typedef struct {
535f4613f2SJohn Marino     char *text;
545f4613f2SJohn Marino     size_t used;
555f4613f2SJohn Marino     size_t size;
565f4613f2SJohn Marino } DYNBUF;
575f4613f2SJohn Marino 
585f4613f2SJohn Marino static int tversion;		/* terminfo version */
595f4613f2SJohn Marino static int outform;		/* output format to use */
605f4613f2SJohn Marino static int sortmode;		/* sort mode to use */
615f4613f2SJohn Marino static int width = 60;		/* max line width for listings */
623468e90cSJohn Marino static int height = 65535;	/* max number of lines for listings */
635f4613f2SJohn Marino static int column;		/* current column, limited by 'width' */
645f4613f2SJohn Marino static int oldcol;		/* last value of column before wrap */
655f4613f2SJohn Marino static bool pretty;		/* true if we format if-then-else strings */
66*32bb5217SDaniel Fojt static bool wrapped;		/* true if we wrap too-long strings */
67*32bb5217SDaniel Fojt static bool did_wrap;		/* true if last wrap_concat did wrapping */
683468e90cSJohn Marino static bool checking;		/* true if we are checking for tic */
693468e90cSJohn Marino static int quickdump;		/* true if we are dumping compiled data */
705f4613f2SJohn Marino 
715f4613f2SJohn Marino static char *save_sgr;
725f4613f2SJohn Marino 
735f4613f2SJohn Marino static DYNBUF outbuf;
745f4613f2SJohn Marino static DYNBUF tmpbuf;
755f4613f2SJohn Marino 
765f4613f2SJohn Marino /* indirection pointers for implementing sort and display modes */
775f4613f2SJohn Marino static const PredIdx *bool_indirect, *num_indirect, *str_indirect;
785f4613f2SJohn Marino static NCURSES_CONST char *const *bool_names;
795f4613f2SJohn Marino static NCURSES_CONST char *const *num_names;
805f4613f2SJohn Marino static NCURSES_CONST char *const *str_names;
815f4613f2SJohn Marino 
823468e90cSJohn Marino static const char *separator = "", *trailer = "";
833468e90cSJohn Marino static int indent = 8;
845f4613f2SJohn Marino 
855f4613f2SJohn Marino /* cover various ports and variants of terminfo */
865f4613f2SJohn Marino #define V_ALLCAPS	0	/* all capabilities (SVr4, XSI, ncurses) */
875f4613f2SJohn Marino #define V_SVR1		1	/* SVR1, Ultrix */
885f4613f2SJohn Marino #define V_HPUX		2	/* HP/UX */
895f4613f2SJohn Marino #define V_AIX		3	/* AIX */
905f4613f2SJohn Marino #define V_BSD		4	/* BSD */
915f4613f2SJohn Marino 
925f4613f2SJohn Marino #if NCURSES_XNAMES
935f4613f2SJohn Marino #define OBSOLETE(n) (!_nc_user_definable && (n[0] == 'O' && n[1] == 'T'))
945f4613f2SJohn Marino #else
955f4613f2SJohn Marino #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
965f4613f2SJohn Marino #endif
975f4613f2SJohn Marino 
98*32bb5217SDaniel Fojt #define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && (sortmode != S_VARIABLE) && OBSOLETE(n))
995f4613f2SJohn Marino 
1005f4613f2SJohn Marino #if NCURSES_XNAMES
1015f4613f2SJohn Marino #define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
1025f4613f2SJohn Marino #define NumIndirect(j)  ((j >= NUMCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
1035f4613f2SJohn Marino #define StrIndirect(j)  ((j >= STRCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
1045f4613f2SJohn Marino #else
1055f4613f2SJohn Marino #define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
1065f4613f2SJohn Marino #define NumIndirect(j)  ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
1075f4613f2SJohn Marino #define StrIndirect(j)  ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
1085f4613f2SJohn Marino #endif
1095f4613f2SJohn Marino 
1103468e90cSJohn Marino static void failed(const char *) GCC_NORETURN;
1113468e90cSJohn Marino 
1123468e90cSJohn Marino static void
failed(const char * s)1133468e90cSJohn Marino failed(const char *s)
1143468e90cSJohn Marino {
1153468e90cSJohn Marino     perror(s);
1163468e90cSJohn Marino     ExitProgram(EXIT_FAILURE);
1173468e90cSJohn Marino }
1183468e90cSJohn Marino 
1195f4613f2SJohn Marino static void
strncpy_DYN(DYNBUF * dst,const char * src,size_t need)1205f4613f2SJohn Marino strncpy_DYN(DYNBUF * dst, const char *src, size_t need)
1215f4613f2SJohn Marino {
1225f4613f2SJohn Marino     size_t want = need + dst->used + 1;
1235f4613f2SJohn Marino     if (want > dst->size) {
1245f4613f2SJohn Marino 	dst->size += (want + 1024);	/* be generous */
1255f4613f2SJohn Marino 	dst->text = typeRealloc(char, dst->size, dst->text);
1263468e90cSJohn Marino 	if (dst->text == 0)
1273468e90cSJohn Marino 	    failed("strncpy_DYN");
1285f4613f2SJohn Marino     }
129*32bb5217SDaniel Fojt     _nc_STRNCPY(dst->text + dst->used, src, need + 1);
1305f4613f2SJohn Marino     dst->used += need;
1315f4613f2SJohn Marino     dst->text[dst->used] = 0;
1325f4613f2SJohn Marino }
1335f4613f2SJohn Marino 
1345f4613f2SJohn Marino static void
strcpy_DYN(DYNBUF * dst,const char * src)1355f4613f2SJohn Marino strcpy_DYN(DYNBUF * dst, const char *src)
1365f4613f2SJohn Marino {
1375f4613f2SJohn Marino     if (src == 0) {
1385f4613f2SJohn Marino 	dst->used = 0;
1395f4613f2SJohn Marino 	strcpy_DYN(dst, "");
1405f4613f2SJohn Marino     } else {
1415f4613f2SJohn Marino 	strncpy_DYN(dst, src, strlen(src));
1425f4613f2SJohn Marino     }
1435f4613f2SJohn Marino }
1445f4613f2SJohn Marino 
1455f4613f2SJohn Marino #if NO_LEAKS
1465f4613f2SJohn Marino static void
free_DYN(DYNBUF * p)1475f4613f2SJohn Marino free_DYN(DYNBUF * p)
1485f4613f2SJohn Marino {
1495f4613f2SJohn Marino     if (p->text != 0)
1505f4613f2SJohn Marino 	free(p->text);
1515f4613f2SJohn Marino     p->text = 0;
1525f4613f2SJohn Marino     p->size = 0;
1535f4613f2SJohn Marino     p->used = 0;
1545f4613f2SJohn Marino }
1555f4613f2SJohn Marino 
1565f4613f2SJohn Marino void
_nc_leaks_dump_entry(void)1575f4613f2SJohn Marino _nc_leaks_dump_entry(void)
1585f4613f2SJohn Marino {
1595f4613f2SJohn Marino     free_DYN(&outbuf);
1605f4613f2SJohn Marino     free_DYN(&tmpbuf);
1615f4613f2SJohn Marino }
1625f4613f2SJohn Marino #endif
1635f4613f2SJohn Marino 
1645f4613f2SJohn Marino #define NameTrans(check,result) \
1653468e90cSJohn Marino 	    if ((np->nte_index <= OK_ ## check) \
1665f4613f2SJohn Marino 		&& check[np->nte_index]) \
1675f4613f2SJohn Marino 		return (result[np->nte_index])
1685f4613f2SJohn Marino 
1695f4613f2SJohn Marino NCURSES_CONST char *
nametrans(const char * name)1705f4613f2SJohn Marino nametrans(const char *name)
1713468e90cSJohn Marino /* translate a capability name to termcap from terminfo */
1725f4613f2SJohn Marino {
1735f4613f2SJohn Marino     const struct name_table_entry *np;
1745f4613f2SJohn Marino 
1753468e90cSJohn Marino     if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) {
1765f4613f2SJohn Marino 	switch (np->nte_type) {
1775f4613f2SJohn Marino 	case BOOLEAN:
1785f4613f2SJohn Marino 	    NameTrans(bool_from_termcap, boolcodes);
1795f4613f2SJohn Marino 	    break;
1805f4613f2SJohn Marino 
1815f4613f2SJohn Marino 	case NUMBER:
1825f4613f2SJohn Marino 	    NameTrans(num_from_termcap, numcodes);
1835f4613f2SJohn Marino 	    break;
1845f4613f2SJohn Marino 
1855f4613f2SJohn Marino 	case STRING:
1865f4613f2SJohn Marino 	    NameTrans(str_from_termcap, strcodes);
1875f4613f2SJohn Marino 	    break;
1885f4613f2SJohn Marino 	}
1893468e90cSJohn Marino     }
1905f4613f2SJohn Marino 
1915f4613f2SJohn Marino     return (0);
1925f4613f2SJohn Marino }
1935f4613f2SJohn Marino 
1945f4613f2SJohn Marino void
dump_init(const char * version,int mode,int sort,bool wrap_strings,int twidth,int theight,unsigned traceval,bool formatted,bool check,int quick)1953468e90cSJohn Marino dump_init(const char *version,
1963468e90cSJohn Marino 	  int mode,
1973468e90cSJohn Marino 	  int sort,
198*32bb5217SDaniel Fojt 	  bool wrap_strings,
1993468e90cSJohn Marino 	  int twidth,
2003468e90cSJohn Marino 	  int theight,
2013468e90cSJohn Marino 	  unsigned traceval,
2023468e90cSJohn Marino 	  bool formatted,
2033468e90cSJohn Marino 	  bool check,
2043468e90cSJohn Marino 	  int quick)
2055f4613f2SJohn Marino /* set up for entry display */
2065f4613f2SJohn Marino {
2075f4613f2SJohn Marino     width = twidth;
2083468e90cSJohn Marino     height = theight;
2095f4613f2SJohn Marino     pretty = formatted;
210*32bb5217SDaniel Fojt     wrapped = wrap_strings;
2113468e90cSJohn Marino     checking = check;
2123468e90cSJohn Marino     quickdump = (quick & 3);
2135f4613f2SJohn Marino 
214*32bb5217SDaniel Fojt     did_wrap = (width <= 0);
215*32bb5217SDaniel Fojt 
2165f4613f2SJohn Marino     /* versions */
2175f4613f2SJohn Marino     if (version == 0)
2185f4613f2SJohn Marino 	tversion = V_ALLCAPS;
2195f4613f2SJohn Marino     else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
2205f4613f2SJohn Marino 	     || !strcmp(version, "Ultrix"))
2215f4613f2SJohn Marino 	tversion = V_SVR1;
2225f4613f2SJohn Marino     else if (!strcmp(version, "HP"))
2235f4613f2SJohn Marino 	tversion = V_HPUX;
2245f4613f2SJohn Marino     else if (!strcmp(version, "AIX"))
2255f4613f2SJohn Marino 	tversion = V_AIX;
2265f4613f2SJohn Marino     else if (!strcmp(version, "BSD"))
2275f4613f2SJohn Marino 	tversion = V_BSD;
2285f4613f2SJohn Marino     else
2295f4613f2SJohn Marino 	tversion = V_ALLCAPS;
2305f4613f2SJohn Marino 
2315f4613f2SJohn Marino     /* implement display modes */
2325f4613f2SJohn Marino     switch (outform = mode) {
2335f4613f2SJohn Marino     case F_LITERAL:
2345f4613f2SJohn Marino     case F_TERMINFO:
2355f4613f2SJohn Marino 	bool_names = boolnames;
2365f4613f2SJohn Marino 	num_names = numnames;
2375f4613f2SJohn Marino 	str_names = strnames;
2383468e90cSJohn Marino 	separator = (twidth > 0 && theight > 1) ? ", " : ",";
2395f4613f2SJohn Marino 	trailer = "\n\t";
2405f4613f2SJohn Marino 	break;
2415f4613f2SJohn Marino 
2425f4613f2SJohn Marino     case F_VARIABLE:
2435f4613f2SJohn Marino 	bool_names = boolfnames;
2445f4613f2SJohn Marino 	num_names = numfnames;
2455f4613f2SJohn Marino 	str_names = strfnames;
2463468e90cSJohn Marino 	separator = (twidth > 0 && theight > 1) ? ", " : ",";
2475f4613f2SJohn Marino 	trailer = "\n\t";
2485f4613f2SJohn Marino 	break;
2495f4613f2SJohn Marino 
2505f4613f2SJohn Marino     case F_TERMCAP:
2515f4613f2SJohn Marino     case F_TCONVERR:
2525f4613f2SJohn Marino 	bool_names = boolcodes;
2535f4613f2SJohn Marino 	num_names = numcodes;
2545f4613f2SJohn Marino 	str_names = strcodes;
2555f4613f2SJohn Marino 	separator = ":";
2565f4613f2SJohn Marino 	trailer = "\\\n\t:";
2575f4613f2SJohn Marino 	break;
2585f4613f2SJohn Marino     }
2593468e90cSJohn Marino     indent = 8;
2605f4613f2SJohn Marino 
2615f4613f2SJohn Marino     /* implement sort modes */
2625f4613f2SJohn Marino     switch (sortmode = sort) {
2635f4613f2SJohn Marino     case S_NOSORT:
2645f4613f2SJohn Marino 	if (traceval)
2655f4613f2SJohn Marino 	    (void) fprintf(stderr,
2665f4613f2SJohn Marino 			   "%s: sorting by term structure order\n", _nc_progname);
2675f4613f2SJohn Marino 	break;
2685f4613f2SJohn Marino 
2695f4613f2SJohn Marino     case S_TERMINFO:
2705f4613f2SJohn Marino 	if (traceval)
2715f4613f2SJohn Marino 	    (void) fprintf(stderr,
2725f4613f2SJohn Marino 			   "%s: sorting by terminfo name order\n", _nc_progname);
2735f4613f2SJohn Marino 	bool_indirect = bool_terminfo_sort;
2745f4613f2SJohn Marino 	num_indirect = num_terminfo_sort;
2755f4613f2SJohn Marino 	str_indirect = str_terminfo_sort;
2765f4613f2SJohn Marino 	break;
2775f4613f2SJohn Marino 
2785f4613f2SJohn Marino     case S_VARIABLE:
2795f4613f2SJohn Marino 	if (traceval)
2805f4613f2SJohn Marino 	    (void) fprintf(stderr,
2815f4613f2SJohn Marino 			   "%s: sorting by C variable order\n", _nc_progname);
2825f4613f2SJohn Marino 	bool_indirect = bool_variable_sort;
2835f4613f2SJohn Marino 	num_indirect = num_variable_sort;
2845f4613f2SJohn Marino 	str_indirect = str_variable_sort;
2855f4613f2SJohn Marino 	break;
2865f4613f2SJohn Marino 
2875f4613f2SJohn Marino     case S_TERMCAP:
2885f4613f2SJohn Marino 	if (traceval)
2895f4613f2SJohn Marino 	    (void) fprintf(stderr,
2905f4613f2SJohn Marino 			   "%s: sorting by termcap name order\n", _nc_progname);
2915f4613f2SJohn Marino 	bool_indirect = bool_termcap_sort;
2925f4613f2SJohn Marino 	num_indirect = num_termcap_sort;
2935f4613f2SJohn Marino 	str_indirect = str_termcap_sort;
2945f4613f2SJohn Marino 	break;
2955f4613f2SJohn Marino     }
2965f4613f2SJohn Marino 
2975f4613f2SJohn Marino     if (traceval)
2985f4613f2SJohn Marino 	(void) fprintf(stderr,
2995f4613f2SJohn Marino 		       "%s: width = %d, tversion = %d, outform = %d\n",
3005f4613f2SJohn Marino 		       _nc_progname, width, tversion, outform);
3015f4613f2SJohn Marino }
3025f4613f2SJohn Marino 
303*32bb5217SDaniel Fojt static TERMTYPE2 *cur_type;
3045f4613f2SJohn Marino 
3055f4613f2SJohn Marino static int
dump_predicate(PredType type,PredIdx idx)3065f4613f2SJohn Marino dump_predicate(PredType type, PredIdx idx)
3075f4613f2SJohn Marino /* predicate function to use for ordinary decompilation */
3085f4613f2SJohn Marino {
3095f4613f2SJohn Marino     switch (type) {
3105f4613f2SJohn Marino     case BOOLEAN:
3115f4613f2SJohn Marino 	return (cur_type->Booleans[idx] == FALSE)
3125f4613f2SJohn Marino 	    ? FAIL : cur_type->Booleans[idx];
3135f4613f2SJohn Marino 
3145f4613f2SJohn Marino     case NUMBER:
3155f4613f2SJohn Marino 	return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
3165f4613f2SJohn Marino 	    ? FAIL : cur_type->Numbers[idx];
3175f4613f2SJohn Marino 
3185f4613f2SJohn Marino     case STRING:
3195f4613f2SJohn Marino 	return (cur_type->Strings[idx] != ABSENT_STRING)
3205f4613f2SJohn Marino 	    ? (int) TRUE : FAIL;
3215f4613f2SJohn Marino     }
3225f4613f2SJohn Marino 
3235f4613f2SJohn Marino     return (FALSE);		/* pacify compiler */
3245f4613f2SJohn Marino }
3255f4613f2SJohn Marino 
326*32bb5217SDaniel Fojt static void set_obsolete_termcaps(TERMTYPE2 *tp);
3275f4613f2SJohn Marino 
3285f4613f2SJohn Marino /* is this the index of a function key string? */
3293468e90cSJohn Marino #define FNKEY(i) \
3303468e90cSJohn Marino     (((i) >= STR_IDX(key_f0) && \
3313468e90cSJohn Marino       (i) <= STR_IDX(key_f9)) || \
3323468e90cSJohn Marino      ((i) >= STR_IDX(key_f11) && \
3333468e90cSJohn Marino       (i) <= STR_IDX(key_f63)))
3345f4613f2SJohn Marino 
3355f4613f2SJohn Marino /*
3365f4613f2SJohn Marino  * If we configure with a different Caps file, the offsets into the arrays
3375f4613f2SJohn Marino  * will change.  So we use an address expression.
3385f4613f2SJohn Marino  */
3395f4613f2SJohn Marino #define BOOL_IDX(name) (PredType) (&(name) - &(CUR Booleans[0]))
3405f4613f2SJohn Marino #define NUM_IDX(name)  (PredType) (&(name) - &(CUR Numbers[0]))
3415f4613f2SJohn Marino #define STR_IDX(name)  (PredType) (&(name) - &(CUR Strings[0]))
3425f4613f2SJohn Marino 
3435f4613f2SJohn Marino static bool
version_filter(PredType type,PredIdx idx)3445f4613f2SJohn Marino version_filter(PredType type, PredIdx idx)
3455f4613f2SJohn Marino /* filter out capabilities we may want to suppress */
3465f4613f2SJohn Marino {
3475f4613f2SJohn Marino     switch (tversion) {
3485f4613f2SJohn Marino     case V_ALLCAPS:		/* SVr4, XSI Curses */
3495f4613f2SJohn Marino 	return (TRUE);
3505f4613f2SJohn Marino 
3515f4613f2SJohn Marino     case V_SVR1:		/* System V Release 1, Ultrix */
3525f4613f2SJohn Marino 	switch (type) {
3535f4613f2SJohn Marino 	case BOOLEAN:
3545f4613f2SJohn Marino 	    return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
3555f4613f2SJohn Marino 	case NUMBER:
3565f4613f2SJohn Marino 	    return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
3575f4613f2SJohn Marino 	case STRING:
3585f4613f2SJohn Marino 	    return ((idx <= STR_IDX(prtr_non)) ? TRUE : FALSE);
3595f4613f2SJohn Marino 	}
3605f4613f2SJohn Marino 	break;
3615f4613f2SJohn Marino 
3625f4613f2SJohn Marino     case V_HPUX:		/* Hewlett-Packard */
3635f4613f2SJohn Marino 	switch (type) {
3645f4613f2SJohn Marino 	case BOOLEAN:
3655f4613f2SJohn Marino 	    return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
3665f4613f2SJohn Marino 	case NUMBER:
3675f4613f2SJohn Marino 	    return ((idx <= NUM_IDX(label_width)) ? TRUE : FALSE);
3685f4613f2SJohn Marino 	case STRING:
3695f4613f2SJohn Marino 	    if (idx <= STR_IDX(prtr_non))
3705f4613f2SJohn Marino 		return (TRUE);
3715f4613f2SJohn Marino 	    else if (FNKEY(idx))	/* function keys */
3725f4613f2SJohn Marino 		return (TRUE);
3735f4613f2SJohn Marino 	    else if (idx == STR_IDX(plab_norm)
3745f4613f2SJohn Marino 		     || idx == STR_IDX(label_on)
3755f4613f2SJohn Marino 		     || idx == STR_IDX(label_off))
3765f4613f2SJohn Marino 		return (TRUE);
3775f4613f2SJohn Marino 	    else
3785f4613f2SJohn Marino 		return (FALSE);
3795f4613f2SJohn Marino 	}
3805f4613f2SJohn Marino 	break;
3815f4613f2SJohn Marino 
3825f4613f2SJohn Marino     case V_AIX:		/* AIX */
3835f4613f2SJohn Marino 	switch (type) {
3845f4613f2SJohn Marino 	case BOOLEAN:
3855f4613f2SJohn Marino 	    return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
3865f4613f2SJohn Marino 	case NUMBER:
3875f4613f2SJohn Marino 	    return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
3885f4613f2SJohn Marino 	case STRING:
3895f4613f2SJohn Marino 	    if (idx <= STR_IDX(prtr_non))
3905f4613f2SJohn Marino 		return (TRUE);
3915f4613f2SJohn Marino 	    else if (FNKEY(idx))	/* function keys */
3925f4613f2SJohn Marino 		return (TRUE);
3935f4613f2SJohn Marino 	    else
3945f4613f2SJohn Marino 		return (FALSE);
3955f4613f2SJohn Marino 	}
3965f4613f2SJohn Marino 	break;
3975f4613f2SJohn Marino 
3985f4613f2SJohn Marino #define is_termcap(type) (OkIndex(idx, type##_from_termcap) && \
3995f4613f2SJohn Marino 			  type##_from_termcap[idx])
4005f4613f2SJohn Marino 
4015f4613f2SJohn Marino     case V_BSD:		/* BSD */
4025f4613f2SJohn Marino 	switch (type) {
4035f4613f2SJohn Marino 	case BOOLEAN:
4045f4613f2SJohn Marino 	    return is_termcap(bool);
4055f4613f2SJohn Marino 	case NUMBER:
4065f4613f2SJohn Marino 	    return is_termcap(num);
4075f4613f2SJohn Marino 	case STRING:
4085f4613f2SJohn Marino 	    return is_termcap(str);
4095f4613f2SJohn Marino 	}
4105f4613f2SJohn Marino 	break;
4115f4613f2SJohn Marino     }
4125f4613f2SJohn Marino 
4135f4613f2SJohn Marino     return (FALSE);		/* pacify the compiler */
4145f4613f2SJohn Marino }
4155f4613f2SJohn Marino 
4165f4613f2SJohn Marino static void
trim_trailing(void)4175f4613f2SJohn Marino trim_trailing(void)
4185f4613f2SJohn Marino {
4195f4613f2SJohn Marino     while (outbuf.used > 0 && outbuf.text[outbuf.used - 1] == ' ')
4205f4613f2SJohn Marino 	outbuf.text[--outbuf.used] = '\0';
4215f4613f2SJohn Marino }
4225f4613f2SJohn Marino 
4235f4613f2SJohn Marino static void
force_wrap(void)4245f4613f2SJohn Marino force_wrap(void)
4255f4613f2SJohn Marino {
4265f4613f2SJohn Marino     oldcol = column;
4275f4613f2SJohn Marino     trim_trailing();
4285f4613f2SJohn Marino     strcpy_DYN(&outbuf, trailer);
4293468e90cSJohn Marino     column = indent;
4305f4613f2SJohn Marino }
4315f4613f2SJohn Marino 
432*32bb5217SDaniel Fojt static int
op_length(const char * src,int offset)433*32bb5217SDaniel Fojt op_length(const char *src, int offset)
4345f4613f2SJohn Marino {
435*32bb5217SDaniel Fojt     int result = 0;
436*32bb5217SDaniel Fojt     int ch;
437*32bb5217SDaniel Fojt     if (offset > 0 && src[offset - 1] == '\\') {
438*32bb5217SDaniel Fojt 	result = 0;
439*32bb5217SDaniel Fojt     } else {
440*32bb5217SDaniel Fojt 	result++;		/* for '%' mark */
441*32bb5217SDaniel Fojt 	ch = src[offset + result];
442*32bb5217SDaniel Fojt 	if (TcOutput()) {
443*32bb5217SDaniel Fojt 	    if (ch == '>') {
444*32bb5217SDaniel Fojt 		result += 3;
445*32bb5217SDaniel Fojt 	    } else if (ch == '+') {
446*32bb5217SDaniel Fojt 		result += 2;
447*32bb5217SDaniel Fojt 	    } else {
448*32bb5217SDaniel Fojt 		result++;
449*32bb5217SDaniel Fojt 	    }
450*32bb5217SDaniel Fojt 	} else if (ch == '\'') {
451*32bb5217SDaniel Fojt 	    result += 3;
452*32bb5217SDaniel Fojt 	} else if (ch == L_CURL[0]) {
453*32bb5217SDaniel Fojt 	    int n = result;
454*32bb5217SDaniel Fojt 	    while ((ch = src[offset + n]) != '\0') {
455*32bb5217SDaniel Fojt 		if (ch == R_CURL[0]) {
456*32bb5217SDaniel Fojt 		    result = ++n;
457*32bb5217SDaniel Fojt 		    break;
458*32bb5217SDaniel Fojt 		}
459*32bb5217SDaniel Fojt 		n++;
460*32bb5217SDaniel Fojt 	    }
461*32bb5217SDaniel Fojt 	} else if (strchr("pPg", ch) != 0) {
462*32bb5217SDaniel Fojt 	    result += 2;
463*32bb5217SDaniel Fojt 	} else {
464*32bb5217SDaniel Fojt 	    result++;		/* ordinary operator */
465*32bb5217SDaniel Fojt 	}
466*32bb5217SDaniel Fojt     }
467*32bb5217SDaniel Fojt     return result;
468*32bb5217SDaniel Fojt }
4695f4613f2SJohn Marino 
470*32bb5217SDaniel Fojt /*
471*32bb5217SDaniel Fojt  * When wrapping too-long strings, avoid splitting a backslash sequence, or
472*32bb5217SDaniel Fojt  * a terminfo '%' operator.  That will leave things a little ragged, but avoids
473*32bb5217SDaniel Fojt  * a stray backslash at the end of the line, as well as making the result a
474*32bb5217SDaniel Fojt  * little more readable.
475*32bb5217SDaniel Fojt  */
476*32bb5217SDaniel Fojt static int
find_split(const char * src,int step,int size)477*32bb5217SDaniel Fojt find_split(const char *src, int step, int size)
478*32bb5217SDaniel Fojt {
479*32bb5217SDaniel Fojt     int result = size;
480*32bb5217SDaniel Fojt     int n;
481*32bb5217SDaniel Fojt     if (size > 0) {
482*32bb5217SDaniel Fojt 	/* check if that would split a backslash-sequence */
483*32bb5217SDaniel Fojt 	int mark = size;
484*32bb5217SDaniel Fojt 	for (n = size - 1; n > 0; --n) {
485*32bb5217SDaniel Fojt 	    int ch = UChar(src[step + n]);
486*32bb5217SDaniel Fojt 	    if (ch == '\\') {
487*32bb5217SDaniel Fojt 		if (n > 0 && src[step + n - 1] == ch)
488*32bb5217SDaniel Fojt 		    --n;
489*32bb5217SDaniel Fojt 		mark = n;
490*32bb5217SDaniel Fojt 		break;
491*32bb5217SDaniel Fojt 	    } else if (!isalnum(ch)) {
492*32bb5217SDaniel Fojt 		break;
493*32bb5217SDaniel Fojt 	    }
494*32bb5217SDaniel Fojt 	}
495*32bb5217SDaniel Fojt 	if (mark < size) {
496*32bb5217SDaniel Fojt 	    result = mark;
497*32bb5217SDaniel Fojt 	} else {
498*32bb5217SDaniel Fojt 	    /* check if that would split a backslash-sequence */
499*32bb5217SDaniel Fojt 	    for (n = size - 1; n > 0; --n) {
500*32bb5217SDaniel Fojt 		int ch = UChar(src[step + n]);
501*32bb5217SDaniel Fojt 		if (ch == '%') {
502*32bb5217SDaniel Fojt 		    int need = op_length(src, step + n);
503*32bb5217SDaniel Fojt 		    if ((n + need) > size) {
504*32bb5217SDaniel Fojt 			mark = n;
505*32bb5217SDaniel Fojt 		    }
506*32bb5217SDaniel Fojt 		    break;
507*32bb5217SDaniel Fojt 		}
508*32bb5217SDaniel Fojt 	    }
509*32bb5217SDaniel Fojt 	    if (mark < size) {
510*32bb5217SDaniel Fojt 		result = mark;
511*32bb5217SDaniel Fojt 	    }
512*32bb5217SDaniel Fojt 	}
513*32bb5217SDaniel Fojt     }
514*32bb5217SDaniel Fojt     return result;
515*32bb5217SDaniel Fojt }
516*32bb5217SDaniel Fojt 
517*32bb5217SDaniel Fojt /*
518*32bb5217SDaniel Fojt  * If we are going to wrap lines, we cannot leave literal spaces because that
519*32bb5217SDaniel Fojt  * would be ambiguous if we split on that space.
520*32bb5217SDaniel Fojt  */
521*32bb5217SDaniel Fojt static char *
fill_spaces(const char * src)522*32bb5217SDaniel Fojt fill_spaces(const char *src)
523*32bb5217SDaniel Fojt {
524*32bb5217SDaniel Fojt     const char *fill = "\\s";
525*32bb5217SDaniel Fojt     size_t need = strlen(src);
526*32bb5217SDaniel Fojt     size_t size = strlen(fill);
527*32bb5217SDaniel Fojt     char *result = 0;
528*32bb5217SDaniel Fojt     int pass;
529*32bb5217SDaniel Fojt     int s, d;
530*32bb5217SDaniel Fojt     for (pass = 0; pass < 2; ++pass) {
531*32bb5217SDaniel Fojt 	for (s = d = 0; src[s] != '\0'; ++s) {
532*32bb5217SDaniel Fojt 	    if (src[s] == ' ') {
533*32bb5217SDaniel Fojt 		if (pass) {
534*32bb5217SDaniel Fojt 		    _nc_STRCPY(&result[d], fill, need + 1 - d);
535*32bb5217SDaniel Fojt 		    d += (int) size;
536*32bb5217SDaniel Fojt 		} else {
537*32bb5217SDaniel Fojt 		    need += size;
538*32bb5217SDaniel Fojt 		}
539*32bb5217SDaniel Fojt 	    } else {
540*32bb5217SDaniel Fojt 		if (pass) {
541*32bb5217SDaniel Fojt 		    result[d++] = src[s];
542*32bb5217SDaniel Fojt 		} else {
543*32bb5217SDaniel Fojt 		    ++d;
544*32bb5217SDaniel Fojt 		}
545*32bb5217SDaniel Fojt 	    }
546*32bb5217SDaniel Fojt 	}
547*32bb5217SDaniel Fojt 	if (pass) {
548*32bb5217SDaniel Fojt 	    result[d] = '\0';
549*32bb5217SDaniel Fojt 	} else {
550*32bb5217SDaniel Fojt 	    result = malloc(need + 1);
551*32bb5217SDaniel Fojt 	    if (result == 0)
552*32bb5217SDaniel Fojt 		failed("fill_spaces");
553*32bb5217SDaniel Fojt 	}
554*32bb5217SDaniel Fojt     }
555*32bb5217SDaniel Fojt     return result;
556*32bb5217SDaniel Fojt }
557*32bb5217SDaniel Fojt 
558*32bb5217SDaniel Fojt typedef enum {
559*32bb5217SDaniel Fojt     wOFF = 0
560*32bb5217SDaniel Fojt     ,w1ST = 1
561*32bb5217SDaniel Fojt     ,w2ND = 2
562*32bb5217SDaniel Fojt     ,wEND = 4
563*32bb5217SDaniel Fojt     ,wERR = 8
564*32bb5217SDaniel Fojt } WRAPMODE;
565*32bb5217SDaniel Fojt 
566*32bb5217SDaniel Fojt #define wrap_1ST(mode) ((mode)&w1ST)
567*32bb5217SDaniel Fojt #define wrap_END(mode) ((mode)&wEND)
568*32bb5217SDaniel Fojt #define wrap_ERR(mode) ((mode)&wERR)
569*32bb5217SDaniel Fojt 
570*32bb5217SDaniel Fojt static void
wrap_concat(const char * src,int need,unsigned mode)571*32bb5217SDaniel Fojt wrap_concat(const char *src, int need, unsigned mode)
572*32bb5217SDaniel Fojt {
573*32bb5217SDaniel Fojt     int gaps = (int) strlen(separator);
574*32bb5217SDaniel Fojt     int want = gaps + need;
575*32bb5217SDaniel Fojt 
576*32bb5217SDaniel Fojt     did_wrap = (width <= 0);
577*32bb5217SDaniel Fojt     if (wrap_1ST(mode)
578*32bb5217SDaniel Fojt 	&& column > indent
579*32bb5217SDaniel Fojt 	&& column + want > width) {
5805f4613f2SJohn Marino 	force_wrap();
5815f4613f2SJohn Marino     }
582*32bb5217SDaniel Fojt     if ((wrap_END(mode) && !wrap_ERR(mode)) &&
583*32bb5217SDaniel Fojt 	wrapped &&
584*32bb5217SDaniel Fojt 	(width >= 0) &&
585*32bb5217SDaniel Fojt 	(column + want) > width) {
586*32bb5217SDaniel Fojt 	int step = 0;
587*32bb5217SDaniel Fojt 	int used = width > WRAPPED ? width : WRAPPED;
588*32bb5217SDaniel Fojt 	int size;
589*32bb5217SDaniel Fojt 	int base = 0;
590*32bb5217SDaniel Fojt 	char *p, align[9];
591*32bb5217SDaniel Fojt 	const char *my_t = trailer;
592*32bb5217SDaniel Fojt 	char *fill = fill_spaces(src);
593*32bb5217SDaniel Fojt 	int last = (int) strlen(fill);
594*32bb5217SDaniel Fojt 
595*32bb5217SDaniel Fojt 	need = last;
596*32bb5217SDaniel Fojt 
597*32bb5217SDaniel Fojt 	if (TcOutput())
598*32bb5217SDaniel Fojt 	    trailer = "\\\n\t ";
599*32bb5217SDaniel Fojt 
600*32bb5217SDaniel Fojt 	if (!TcOutput() && (p = strchr(fill, '=')) != 0) {
601*32bb5217SDaniel Fojt 	    base = (int) (p + 1 - fill);
602*32bb5217SDaniel Fojt 	    if (base > 8)
603*32bb5217SDaniel Fojt 		base = 8;
604*32bb5217SDaniel Fojt 	    _nc_SPRINTF(align, _nc_SLIMIT(align) "%*s", base, " ");
605*32bb5217SDaniel Fojt 	} else if (column > 8) {
606*32bb5217SDaniel Fojt 	    base = column - 8;
607*32bb5217SDaniel Fojt 	    if (base > 8)
608*32bb5217SDaniel Fojt 		base = 8;
609*32bb5217SDaniel Fojt 	    _nc_SPRINTF(align, _nc_SLIMIT(align) "%*s", base, " ");
610*32bb5217SDaniel Fojt 	} else {
611*32bb5217SDaniel Fojt 	    align[base] = '\0';
612*32bb5217SDaniel Fojt 	}
613*32bb5217SDaniel Fojt 	/* "pretty" overrides wrapping if it already split the line */
614*32bb5217SDaniel Fojt 	if (!pretty || strchr(fill, '\n') == 0) {
615*32bb5217SDaniel Fojt 	    int tag = 0;
616*32bb5217SDaniel Fojt 
617*32bb5217SDaniel Fojt 	    if (TcOutput() && outbuf.used && !wrap_1ST(mode)) {
618*32bb5217SDaniel Fojt 		tag = 3;
619*32bb5217SDaniel Fojt 	    }
620*32bb5217SDaniel Fojt 
621*32bb5217SDaniel Fojt 	    while ((column + (need + gaps)) > used) {
622*32bb5217SDaniel Fojt 		size = used - tag;
623*32bb5217SDaniel Fojt 		if (step) {
624*32bb5217SDaniel Fojt 		    strcpy_DYN(&outbuf, align);
625*32bb5217SDaniel Fojt 		    size -= base;
626*32bb5217SDaniel Fojt 		}
627*32bb5217SDaniel Fojt 		if (size > (last - step)) {
628*32bb5217SDaniel Fojt 		    size = (last - step);
629*32bb5217SDaniel Fojt 		}
630*32bb5217SDaniel Fojt 		size = find_split(fill, step, size);
631*32bb5217SDaniel Fojt 		strncpy_DYN(&outbuf, fill + step, (size_t) size);
632*32bb5217SDaniel Fojt 		step += size;
633*32bb5217SDaniel Fojt 		need -= size;
634*32bb5217SDaniel Fojt 		if (need > 0) {
635*32bb5217SDaniel Fojt 		    force_wrap();
636*32bb5217SDaniel Fojt 		    did_wrap = TRUE;
637*32bb5217SDaniel Fojt 		    tag = 0;
638*32bb5217SDaniel Fojt 		}
639*32bb5217SDaniel Fojt 	    }
640*32bb5217SDaniel Fojt 	}
641*32bb5217SDaniel Fojt 	if (need > 0) {
642*32bb5217SDaniel Fojt 	    if (step)
643*32bb5217SDaniel Fojt 		strcpy_DYN(&outbuf, align);
644*32bb5217SDaniel Fojt 	    strcpy_DYN(&outbuf, fill + step);
645*32bb5217SDaniel Fojt 	}
646*32bb5217SDaniel Fojt 	if (wrap_END(mode))
6475f4613f2SJohn Marino 	    strcpy_DYN(&outbuf, separator);
648*32bb5217SDaniel Fojt 	trailer = my_t;
649*32bb5217SDaniel Fojt 	force_wrap();
650*32bb5217SDaniel Fojt 
651*32bb5217SDaniel Fojt 	free(fill);
652*32bb5217SDaniel Fojt     } else {
653*32bb5217SDaniel Fojt 	strcpy_DYN(&outbuf, src);
654*32bb5217SDaniel Fojt 	if (wrap_END(mode))
655*32bb5217SDaniel Fojt 	    strcpy_DYN(&outbuf, separator);
656*32bb5217SDaniel Fojt 	column += (int) strlen(src);
657*32bb5217SDaniel Fojt     }
658*32bb5217SDaniel Fojt }
659*32bb5217SDaniel Fojt 
660*32bb5217SDaniel Fojt static void
wrap_concat1(const char * src)661*32bb5217SDaniel Fojt wrap_concat1(const char *src)
662*32bb5217SDaniel Fojt {
663*32bb5217SDaniel Fojt     int need = (int) strlen(src);
664*32bb5217SDaniel Fojt     wrap_concat(src, need, w1ST | wEND);
665*32bb5217SDaniel Fojt }
666*32bb5217SDaniel Fojt 
667*32bb5217SDaniel Fojt static void
wrap_concat3(const char * name,const char * eqls,const char * value)668*32bb5217SDaniel Fojt wrap_concat3(const char *name, const char *eqls, const char *value)
669*32bb5217SDaniel Fojt {
670*32bb5217SDaniel Fojt     int nlen = (int) strlen(name);
671*32bb5217SDaniel Fojt     int elen = (int) strlen(eqls);
672*32bb5217SDaniel Fojt     int vlen = (int) strlen(value);
673*32bb5217SDaniel Fojt 
674*32bb5217SDaniel Fojt     wrap_concat(name, nlen + elen + vlen, w1ST);
675*32bb5217SDaniel Fojt     wrap_concat(eqls, elen + vlen, w2ND);
676*32bb5217SDaniel Fojt     wrap_concat(value, vlen, wEND);
6775f4613f2SJohn Marino }
6785f4613f2SJohn Marino 
6795f4613f2SJohn Marino #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
6805f4613f2SJohn Marino 	if ((size_t)(last - first) > sizeof(sep_trail)-1 \
6815f4613f2SJohn Marino 	 && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
6825f4613f2SJohn Marino 		first += sizeof(sep_trail)-2
6835f4613f2SJohn Marino 
6845f4613f2SJohn Marino /* Returns the nominal length of the buffer assuming it is termcap format,
6855f4613f2SJohn Marino  * i.e., the continuation sequence is treated as a single character ":".
6865f4613f2SJohn Marino  *
6875f4613f2SJohn Marino  * There are several implementations of termcap which read the text into a
6885f4613f2SJohn Marino  * fixed-size buffer.  Generally they strip the newlines from the text, but may
6895f4613f2SJohn Marino  * not do it until after the buffer is read.  Also, "tc=" resolution may be
6905f4613f2SJohn Marino  * expanded in the same buffer.  This function is useful for measuring the size
6915f4613f2SJohn Marino  * of the best fixed-buffer implementation; the worst case may be much worse.
6925f4613f2SJohn Marino  */
6935f4613f2SJohn Marino #ifdef TEST_TERMCAP_LENGTH
6945f4613f2SJohn Marino static int
termcap_length(const char * src)6955f4613f2SJohn Marino termcap_length(const char *src)
6965f4613f2SJohn Marino {
6975f4613f2SJohn Marino     static const char pattern[] = ":\\\n\t:";
6985f4613f2SJohn Marino 
6995f4613f2SJohn Marino     int len = 0;
7005f4613f2SJohn Marino     const char *const t = src + strlen(src);
7015f4613f2SJohn Marino 
7025f4613f2SJohn Marino     while (*src != '\0') {
7035f4613f2SJohn Marino 	IGNORE_SEP_TRAIL(src, t, pattern);
7045f4613f2SJohn Marino 	src++;
7055f4613f2SJohn Marino 	len++;
7065f4613f2SJohn Marino     }
7075f4613f2SJohn Marino     return len;
7085f4613f2SJohn Marino }
7095f4613f2SJohn Marino #else
7105f4613f2SJohn Marino #define termcap_length(src) strlen(src)
7115f4613f2SJohn Marino #endif
7125f4613f2SJohn Marino 
7135f4613f2SJohn Marino static void
indent_DYN(DYNBUF * buffer,int level)7145f4613f2SJohn Marino indent_DYN(DYNBUF * buffer, int level)
7155f4613f2SJohn Marino {
7165f4613f2SJohn Marino     int n;
7175f4613f2SJohn Marino 
7185f4613f2SJohn Marino     for (n = 0; n < level; n++)
7193468e90cSJohn Marino 	strncpy_DYN(buffer, "\t", (size_t) 1);
7205f4613f2SJohn Marino }
7215f4613f2SJohn Marino 
722*32bb5217SDaniel Fojt /*
723*32bb5217SDaniel Fojt  * Check if the current line which was begun consists only of a tab and the
724*32bb5217SDaniel Fojt  * given leading text.
725*32bb5217SDaniel Fojt  */
726*32bb5217SDaniel Fojt static bool
leading_DYN(DYNBUF * buffer,const char * leading)727*32bb5217SDaniel Fojt leading_DYN(DYNBUF * buffer, const char *leading)
728*32bb5217SDaniel Fojt {
729*32bb5217SDaniel Fojt     bool result = FALSE;
730*32bb5217SDaniel Fojt     size_t need = strlen(leading);
731*32bb5217SDaniel Fojt     if (buffer->used > need) {
732*32bb5217SDaniel Fojt 	need = buffer->used - need;
733*32bb5217SDaniel Fojt 	if (!strcmp(buffer->text + need, leading)) {
734*32bb5217SDaniel Fojt 	    result = TRUE;
735*32bb5217SDaniel Fojt 	    while (--need != 0) {
736*32bb5217SDaniel Fojt 		if (buffer->text[need] == '\n') {
737*32bb5217SDaniel Fojt 		    break;
738*32bb5217SDaniel Fojt 		}
739*32bb5217SDaniel Fojt 		if (buffer->text[need] != '\t') {
740*32bb5217SDaniel Fojt 		    result = FALSE;
741*32bb5217SDaniel Fojt 		    break;
742*32bb5217SDaniel Fojt 		}
743*32bb5217SDaniel Fojt 	    }
744*32bb5217SDaniel Fojt 	}
745*32bb5217SDaniel Fojt     }
746*32bb5217SDaniel Fojt     return result;
747*32bb5217SDaniel Fojt }
748*32bb5217SDaniel Fojt 
7493468e90cSJohn Marino bool
has_params(const char * src)7505f4613f2SJohn Marino has_params(const char *src)
7515f4613f2SJohn Marino {
7525f4613f2SJohn Marino     bool result = FALSE;
7535f4613f2SJohn Marino     int len = (int) strlen(src);
7545f4613f2SJohn Marino     int n;
7555f4613f2SJohn Marino     bool ifthen = FALSE;
7565f4613f2SJohn Marino     bool params = FALSE;
7575f4613f2SJohn Marino 
7585f4613f2SJohn Marino     for (n = 0; n < len - 1; ++n) {
7593468e90cSJohn Marino 	if (!strncmp(src + n, "%p", (size_t) 2)) {
7605f4613f2SJohn Marino 	    params = TRUE;
7613468e90cSJohn Marino 	} else if (!strncmp(src + n, "%;", (size_t) 2)) {
7625f4613f2SJohn Marino 	    ifthen = TRUE;
7635f4613f2SJohn Marino 	    result = params;
7645f4613f2SJohn Marino 	    break;
7655f4613f2SJohn Marino 	}
7665f4613f2SJohn Marino     }
7675f4613f2SJohn Marino     if (!ifthen) {
7685f4613f2SJohn Marino 	result = ((len > 50) && params);
7695f4613f2SJohn Marino     }
7705f4613f2SJohn Marino     return result;
7715f4613f2SJohn Marino }
7725f4613f2SJohn Marino 
7735f4613f2SJohn Marino static char *
fmt_complex(TERMTYPE2 * tterm,const char * capability,char * src,int level)774*32bb5217SDaniel Fojt fmt_complex(TERMTYPE2 *tterm, const char *capability, char *src, int level)
7755f4613f2SJohn Marino {
7765f4613f2SJohn Marino     bool percent = FALSE;
7775f4613f2SJohn Marino     bool params = has_params(src);
7785f4613f2SJohn Marino 
7795f4613f2SJohn Marino     while (*src != '\0') {
7805f4613f2SJohn Marino 	switch (*src) {
7813468e90cSJohn Marino 	case '^':
7823468e90cSJohn Marino 	    percent = FALSE;
7833468e90cSJohn Marino 	    strncpy_DYN(&tmpbuf, src++, (size_t) 1);
7843468e90cSJohn Marino 	    break;
7855f4613f2SJohn Marino 	case '\\':
7865f4613f2SJohn Marino 	    percent = FALSE;
7873468e90cSJohn Marino 	    strncpy_DYN(&tmpbuf, src++, (size_t) 1);
7885f4613f2SJohn Marino 	    break;
7895f4613f2SJohn Marino 	case '%':
7905f4613f2SJohn Marino 	    percent = TRUE;
7915f4613f2SJohn Marino 	    break;
7925f4613f2SJohn Marino 	case '?':		/* "if" */
7935f4613f2SJohn Marino 	case 't':		/* "then" */
7945f4613f2SJohn Marino 	case 'e':		/* "else" */
7955f4613f2SJohn Marino 	    if (percent) {
7965f4613f2SJohn Marino 		percent = FALSE;
7975f4613f2SJohn Marino 		tmpbuf.text[tmpbuf.used - 1] = '\n';
7985f4613f2SJohn Marino 		/* treat a "%e" as else-if, on the same level */
7995f4613f2SJohn Marino 		if (*src == 'e') {
8005f4613f2SJohn Marino 		    indent_DYN(&tmpbuf, level);
8013468e90cSJohn Marino 		    strncpy_DYN(&tmpbuf, "%", (size_t) 1);
8023468e90cSJohn Marino 		    strncpy_DYN(&tmpbuf, src, (size_t) 1);
8035f4613f2SJohn Marino 		    src++;
8045f4613f2SJohn Marino 		    params = has_params(src);
8055f4613f2SJohn Marino 		    if (!params && *src != '\0' && *src != '%') {
8063468e90cSJohn Marino 			strncpy_DYN(&tmpbuf, "\n", (size_t) 1);
8075f4613f2SJohn Marino 			indent_DYN(&tmpbuf, level + 1);
8085f4613f2SJohn Marino 		    }
8095f4613f2SJohn Marino 		} else {
8105f4613f2SJohn Marino 		    indent_DYN(&tmpbuf, level + 1);
8113468e90cSJohn Marino 		    strncpy_DYN(&tmpbuf, "%", (size_t) 1);
8123468e90cSJohn Marino 		    strncpy_DYN(&tmpbuf, src, (size_t) 1);
8135f4613f2SJohn Marino 		    if (*src++ == '?') {
8143468e90cSJohn Marino 			src = fmt_complex(tterm, capability, src, level + 1);
8155f4613f2SJohn Marino 			if (*src != '\0' && *src != '%') {
8163468e90cSJohn Marino 			    strncpy_DYN(&tmpbuf, "\n", (size_t) 1);
8175f4613f2SJohn Marino 			    indent_DYN(&tmpbuf, level + 1);
8185f4613f2SJohn Marino 			}
8195f4613f2SJohn Marino 		    } else if (level == 1) {
8203468e90cSJohn Marino 			if (checking)
8213468e90cSJohn Marino 			    _nc_warning("%s: %%%c without %%? in %s",
8223468e90cSJohn Marino 					_nc_first_name(tterm->term_names),
8233468e90cSJohn Marino 					*src, capability);
8245f4613f2SJohn Marino 		    }
8255f4613f2SJohn Marino 		}
8265f4613f2SJohn Marino 		continue;
8275f4613f2SJohn Marino 	    }
8285f4613f2SJohn Marino 	    break;
8295f4613f2SJohn Marino 	case ';':		/* "endif" */
8305f4613f2SJohn Marino 	    if (percent) {
8315f4613f2SJohn Marino 		percent = FALSE;
8325f4613f2SJohn Marino 		if (level > 1) {
8335f4613f2SJohn Marino 		    tmpbuf.text[tmpbuf.used - 1] = '\n';
8345f4613f2SJohn Marino 		    indent_DYN(&tmpbuf, level);
8353468e90cSJohn Marino 		    strncpy_DYN(&tmpbuf, "%", (size_t) 1);
8363468e90cSJohn Marino 		    strncpy_DYN(&tmpbuf, src++, (size_t) 1);
8373468e90cSJohn Marino 		    if (src[0] == '%'
8383468e90cSJohn Marino 			&& src[1] != '\0'
8393468e90cSJohn Marino 			&& (strchr("?e;", src[1])) == 0) {
8403468e90cSJohn Marino 			tmpbuf.text[tmpbuf.used++] = '\n';
8413468e90cSJohn Marino 			indent_DYN(&tmpbuf, level);
8423468e90cSJohn Marino 		    }
8435f4613f2SJohn Marino 		    return src;
8445f4613f2SJohn Marino 		}
8453468e90cSJohn Marino 		if (checking)
8463468e90cSJohn Marino 		    _nc_warning("%s: %%; without %%? in %s",
8473468e90cSJohn Marino 				_nc_first_name(tterm->term_names),
8483468e90cSJohn Marino 				capability);
8495f4613f2SJohn Marino 	    }
8505f4613f2SJohn Marino 	    break;
8515f4613f2SJohn Marino 	case 'p':
852*32bb5217SDaniel Fojt 	    if (percent && params && !leading_DYN(&tmpbuf, "%")) {
8535f4613f2SJohn Marino 		tmpbuf.text[tmpbuf.used - 1] = '\n';
8545f4613f2SJohn Marino 		indent_DYN(&tmpbuf, level + 1);
8553468e90cSJohn Marino 		strncpy_DYN(&tmpbuf, "%", (size_t) 1);
8565f4613f2SJohn Marino 	    }
8575f4613f2SJohn Marino 	    params = FALSE;
8585f4613f2SJohn Marino 	    percent = FALSE;
8595f4613f2SJohn Marino 	    break;
8605f4613f2SJohn Marino 	case ' ':
8613468e90cSJohn Marino 	    strncpy_DYN(&tmpbuf, "\\s", (size_t) 2);
8625f4613f2SJohn Marino 	    ++src;
8635f4613f2SJohn Marino 	    continue;
8645f4613f2SJohn Marino 	default:
8655f4613f2SJohn Marino 	    percent = FALSE;
8665f4613f2SJohn Marino 	    break;
8675f4613f2SJohn Marino 	}
8683468e90cSJohn Marino 	strncpy_DYN(&tmpbuf, src++, (size_t) 1);
8695f4613f2SJohn Marino     }
8705f4613f2SJohn Marino     return src;
8715f4613f2SJohn Marino }
8725f4613f2SJohn Marino 
873*32bb5217SDaniel Fojt /*
874*32bb5217SDaniel Fojt  * Make "large" numbers a little easier to read by showing them in hexadecimal
875*32bb5217SDaniel Fojt  * if they are "close" to a power of two.
876*32bb5217SDaniel Fojt  */
877*32bb5217SDaniel Fojt static const char *
number_format(int value)878*32bb5217SDaniel Fojt number_format(int value)
879*32bb5217SDaniel Fojt {
880*32bb5217SDaniel Fojt     const char *result = "%d";
881*32bb5217SDaniel Fojt     if ((outform != F_TERMCAP) && (value > 255)) {
882*32bb5217SDaniel Fojt 	unsigned long lv = (unsigned long) value;
883*32bb5217SDaniel Fojt 	unsigned long mm;
884*32bb5217SDaniel Fojt 	int bits = sizeof(unsigned long) * 8;
885*32bb5217SDaniel Fojt 	int nn;
886*32bb5217SDaniel Fojt 	for (nn = 8; nn < bits; ++nn) {
887*32bb5217SDaniel Fojt 	    mm = 1UL << nn;
888*32bb5217SDaniel Fojt 	    if ((mm - 16) <= lv && (mm + 16) > lv) {
889*32bb5217SDaniel Fojt 		result = "%#x";
890*32bb5217SDaniel Fojt 		break;
891*32bb5217SDaniel Fojt 	    }
892*32bb5217SDaniel Fojt 	}
893*32bb5217SDaniel Fojt     }
894*32bb5217SDaniel Fojt     return result;
895*32bb5217SDaniel Fojt }
896*32bb5217SDaniel Fojt 
8975f4613f2SJohn Marino #define SAME_CAP(n,cap) (&tterm->Strings[n] == &cap)
8985f4613f2SJohn Marino #define EXTRA_CAP 20
8995f4613f2SJohn Marino 
9005f4613f2SJohn Marino int
fmt_entry(TERMTYPE2 * tterm,PredFunc pred,int content_only,int suppress_untranslatable,int infodump,int numbers)901*32bb5217SDaniel Fojt fmt_entry(TERMTYPE2 *tterm,
9025f4613f2SJohn Marino 	  PredFunc pred,
9033468e90cSJohn Marino 	  int content_only,
9043468e90cSJohn Marino 	  int suppress_untranslatable,
9053468e90cSJohn Marino 	  int infodump,
9065f4613f2SJohn Marino 	  int numbers)
9075f4613f2SJohn Marino {
9085f4613f2SJohn Marino     PredIdx i, j;
9095f4613f2SJohn Marino     char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
9105f4613f2SJohn Marino     char *capability;
9115f4613f2SJohn Marino     NCURSES_CONST char *name;
9125f4613f2SJohn Marino     int predval, len;
9135f4613f2SJohn Marino     PredIdx num_bools = 0;
9145f4613f2SJohn Marino     PredIdx num_values = 0;
9155f4613f2SJohn Marino     PredIdx num_strings = 0;
9165f4613f2SJohn Marino     bool outcount = 0;
9175f4613f2SJohn Marino 
918*32bb5217SDaniel Fojt #define WRAP_CONCAT1(s)		wrap_concat1(s); outcount = TRUE
919*32bb5217SDaniel Fojt #define WRAP_CONCAT		WRAP_CONCAT1(buffer)
9205f4613f2SJohn Marino 
9215f4613f2SJohn Marino     len = 12;			/* terminfo file-header */
9225f4613f2SJohn Marino 
9235f4613f2SJohn Marino     if (pred == 0) {
9245f4613f2SJohn Marino 	cur_type = tterm;
9255f4613f2SJohn Marino 	pred = dump_predicate;
9265f4613f2SJohn Marino     }
9275f4613f2SJohn Marino 
9285f4613f2SJohn Marino     strcpy_DYN(&outbuf, 0);
9295f4613f2SJohn Marino     if (content_only) {
9303468e90cSJohn Marino 	column = indent;	/* FIXME: workaround to prevent empty lines */
9315f4613f2SJohn Marino     } else {
9325f4613f2SJohn Marino 	strcpy_DYN(&outbuf, tterm->term_names);
9333468e90cSJohn Marino 
9343468e90cSJohn Marino 	/*
9353468e90cSJohn Marino 	 * Colon is legal in terminfo descriptions, but not in termcap.
9363468e90cSJohn Marino 	 */
9373468e90cSJohn Marino 	if (!infodump) {
9383468e90cSJohn Marino 	    char *p = outbuf.text;
9393468e90cSJohn Marino 	    while (*p) {
9403468e90cSJohn Marino 		if (*p == ':') {
9413468e90cSJohn Marino 		    *p = '=';
9423468e90cSJohn Marino 		}
9433468e90cSJohn Marino 		++p;
9443468e90cSJohn Marino 	    }
9453468e90cSJohn Marino 	}
9465f4613f2SJohn Marino 	strcpy_DYN(&outbuf, separator);
9475f4613f2SJohn Marino 	column = (int) outbuf.used;
9483468e90cSJohn Marino 	if (height > 1)
9495f4613f2SJohn Marino 	    force_wrap();
9505f4613f2SJohn Marino     }
9515f4613f2SJohn Marino 
9525f4613f2SJohn Marino     for_each_boolean(j, tterm) {
9535f4613f2SJohn Marino 	i = BoolIndirect(j);
9543468e90cSJohn Marino 	name = ExtBoolname(tterm, (int) i, bool_names);
9555f4613f2SJohn Marino 	assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
9565f4613f2SJohn Marino 
9575f4613f2SJohn Marino 	if (!version_filter(BOOLEAN, i))
9585f4613f2SJohn Marino 	    continue;
9595f4613f2SJohn Marino 	else if (isObsolete(outform, name))
9605f4613f2SJohn Marino 	    continue;
9615f4613f2SJohn Marino 
9625f4613f2SJohn Marino 	predval = pred(BOOLEAN, i);
9635f4613f2SJohn Marino 	if (predval != FAIL) {
9643468e90cSJohn Marino 	    _nc_STRCPY(buffer, name, sizeof(buffer));
9655f4613f2SJohn Marino 	    if (predval <= 0)
9663468e90cSJohn Marino 		_nc_STRCAT(buffer, "@", sizeof(buffer));
9675f4613f2SJohn Marino 	    else if (i + 1 > num_bools)
9685f4613f2SJohn Marino 		num_bools = i + 1;
9695f4613f2SJohn Marino 	    WRAP_CONCAT;
9705f4613f2SJohn Marino 	}
9715f4613f2SJohn Marino     }
9725f4613f2SJohn Marino 
9733468e90cSJohn Marino     if (column != indent && height > 1)
9745f4613f2SJohn Marino 	force_wrap();
9755f4613f2SJohn Marino 
9765f4613f2SJohn Marino     for_each_number(j, tterm) {
9775f4613f2SJohn Marino 	i = NumIndirect(j);
9783468e90cSJohn Marino 	name = ExtNumname(tterm, (int) i, num_names);
9795f4613f2SJohn Marino 	assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
9805f4613f2SJohn Marino 
9815f4613f2SJohn Marino 	if (!version_filter(NUMBER, i))
9825f4613f2SJohn Marino 	    continue;
9835f4613f2SJohn Marino 	else if (isObsolete(outform, name))
9845f4613f2SJohn Marino 	    continue;
9855f4613f2SJohn Marino 
9865f4613f2SJohn Marino 	predval = pred(NUMBER, i);
9875f4613f2SJohn Marino 	if (predval != FAIL) {
9885f4613f2SJohn Marino 	    if (tterm->Numbers[i] < 0) {
9893468e90cSJohn Marino 		_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
9903468e90cSJohn Marino 			    "%s@", name);
9915f4613f2SJohn Marino 	    } else {
992*32bb5217SDaniel Fojt 		size_t nn;
9933468e90cSJohn Marino 		_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
994*32bb5217SDaniel Fojt 			    "%s#", name);
995*32bb5217SDaniel Fojt 		nn = strlen(buffer);
996*32bb5217SDaniel Fojt 		_nc_SPRINTF(buffer + nn, _nc_SLIMIT(sizeof(buffer) - nn)
997*32bb5217SDaniel Fojt 			    number_format(tterm->Numbers[i]),
998*32bb5217SDaniel Fojt 			    tterm->Numbers[i]);
9995f4613f2SJohn Marino 		if (i + 1 > num_values)
10005f4613f2SJohn Marino 		    num_values = i + 1;
10015f4613f2SJohn Marino 	    }
10025f4613f2SJohn Marino 	    WRAP_CONCAT;
10035f4613f2SJohn Marino 	}
10045f4613f2SJohn Marino     }
10055f4613f2SJohn Marino 
10063468e90cSJohn Marino     if (column != indent && height > 1)
10075f4613f2SJohn Marino 	force_wrap();
10085f4613f2SJohn Marino 
10095f4613f2SJohn Marino     len += (int) (num_bools
10105f4613f2SJohn Marino 		  + num_values * 2
10115f4613f2SJohn Marino 		  + strlen(tterm->term_names) + 1);
10125f4613f2SJohn Marino     if (len & 1)
10135f4613f2SJohn Marino 	len++;
10145f4613f2SJohn Marino 
10155f4613f2SJohn Marino #undef CUR
10165f4613f2SJohn Marino #define CUR tterm->
10175f4613f2SJohn Marino     if (outform == F_TERMCAP) {
1018*32bb5217SDaniel Fojt 	if (VALID_STRING(termcap_reset)) {
1019*32bb5217SDaniel Fojt 	    if (VALID_STRING(init_3string)
10205f4613f2SJohn Marino 		&& !strcmp(init_3string, termcap_reset))
10215f4613f2SJohn Marino 		DISCARD(init_3string);
10225f4613f2SJohn Marino 
1023*32bb5217SDaniel Fojt 	    if (VALID_STRING(reset_2string)
10245f4613f2SJohn Marino 		&& !strcmp(reset_2string, termcap_reset))
10255f4613f2SJohn Marino 		DISCARD(reset_2string);
10265f4613f2SJohn Marino 	}
10275f4613f2SJohn Marino     }
10285f4613f2SJohn Marino 
10295f4613f2SJohn Marino     for_each_string(j, tterm) {
10305f4613f2SJohn Marino 	i = StrIndirect(j);
10313468e90cSJohn Marino 	name = ExtStrname(tterm, (int) i, str_names);
10325f4613f2SJohn Marino 	assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
10335f4613f2SJohn Marino 
10345f4613f2SJohn Marino 	capability = tterm->Strings[i];
10355f4613f2SJohn Marino 
10365f4613f2SJohn Marino 	if (!version_filter(STRING, i))
10375f4613f2SJohn Marino 	    continue;
10385f4613f2SJohn Marino 	else if (isObsolete(outform, name))
10395f4613f2SJohn Marino 	    continue;
10405f4613f2SJohn Marino 
10415f4613f2SJohn Marino #if NCURSES_XNAMES
10425f4613f2SJohn Marino 	/*
10435f4613f2SJohn Marino 	 * Extended names can be longer than 2 characters, but termcap programs
10445f4613f2SJohn Marino 	 * cannot read those (filter them out).
10455f4613f2SJohn Marino 	 */
10465f4613f2SJohn Marino 	if (outform == F_TERMCAP && (strlen(name) > 2))
10475f4613f2SJohn Marino 	    continue;
10485f4613f2SJohn Marino #endif
10495f4613f2SJohn Marino 
10505f4613f2SJohn Marino 	if (outform == F_TERMCAP) {
10515f4613f2SJohn Marino 	    /*
10525f4613f2SJohn Marino 	     * Some older versions of vi want rmir/smir to be defined
10535f4613f2SJohn Marino 	     * for ich/ich1 to work.  If they're not defined, force
10545f4613f2SJohn Marino 	     * them to be output as defined and empty.
10555f4613f2SJohn Marino 	     */
10565f4613f2SJohn Marino 	    if (PRESENT(insert_character) || PRESENT(parm_ich)) {
10575f4613f2SJohn Marino 		if (SAME_CAP(i, enter_insert_mode)
10585f4613f2SJohn Marino 		    && enter_insert_mode == ABSENT_STRING) {
10593468e90cSJohn Marino 		    _nc_STRCPY(buffer, "im=", sizeof(buffer));
10605f4613f2SJohn Marino 		    WRAP_CONCAT;
10615f4613f2SJohn Marino 		    continue;
10625f4613f2SJohn Marino 		}
10635f4613f2SJohn Marino 
10645f4613f2SJohn Marino 		if (SAME_CAP(i, exit_insert_mode)
10655f4613f2SJohn Marino 		    && exit_insert_mode == ABSENT_STRING) {
10663468e90cSJohn Marino 		    _nc_STRCPY(buffer, "ei=", sizeof(buffer));
10675f4613f2SJohn Marino 		    WRAP_CONCAT;
10685f4613f2SJohn Marino 		    continue;
10695f4613f2SJohn Marino 		}
10705f4613f2SJohn Marino 	    }
10715f4613f2SJohn Marino 	    /*
10725f4613f2SJohn Marino 	     * termcap applications such as screen will be confused if sgr0
10735f4613f2SJohn Marino 	     * is translated to a string containing rmacs.  Filter that out.
10745f4613f2SJohn Marino 	     */
10755f4613f2SJohn Marino 	    if (PRESENT(exit_attribute_mode)) {
10765f4613f2SJohn Marino 		if (SAME_CAP(i, exit_attribute_mode)) {
10775f4613f2SJohn Marino 		    char *trimmed_sgr0;
10785f4613f2SJohn Marino 		    char *my_sgr = set_attributes;
10795f4613f2SJohn Marino 
10805f4613f2SJohn Marino 		    set_attributes = save_sgr;
10815f4613f2SJohn Marino 
10825f4613f2SJohn Marino 		    trimmed_sgr0 = _nc_trim_sgr0(tterm);
1083*32bb5217SDaniel Fojt 		    if (strcmp(capability, trimmed_sgr0)) {
10845f4613f2SJohn Marino 			capability = trimmed_sgr0;
1085*32bb5217SDaniel Fojt 		    } else {
10863468e90cSJohn Marino 			if (trimmed_sgr0 != exit_attribute_mode)
10873468e90cSJohn Marino 			    free(trimmed_sgr0);
10883468e90cSJohn Marino 		    }
10895f4613f2SJohn Marino 
10905f4613f2SJohn Marino 		    set_attributes = my_sgr;
10915f4613f2SJohn Marino 		}
10925f4613f2SJohn Marino 	    }
10935f4613f2SJohn Marino 	}
10945f4613f2SJohn Marino 
10955f4613f2SJohn Marino 	predval = pred(STRING, i);
10965f4613f2SJohn Marino 	buffer[0] = '\0';
10975f4613f2SJohn Marino 
10985f4613f2SJohn Marino 	if (predval != FAIL) {
1099*32bb5217SDaniel Fojt 	    if (VALID_STRING(capability)
11005f4613f2SJohn Marino 		&& i + 1 > num_strings)
11015f4613f2SJohn Marino 		num_strings = i + 1;
11025f4613f2SJohn Marino 
11035f4613f2SJohn Marino 	    if (!VALID_STRING(capability)) {
11043468e90cSJohn Marino 		_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
11053468e90cSJohn Marino 			    "%s@", name);
11065f4613f2SJohn Marino 		WRAP_CONCAT;
1107*32bb5217SDaniel Fojt 	    } else if (TcOutput()) {
11085f4613f2SJohn Marino 		char *srccap = _nc_tic_expand(capability, TRUE, numbers);
1109*32bb5217SDaniel Fojt 		int params = ((i < (int) SIZEOF(parametrized))
11103468e90cSJohn Marino 			      ? parametrized[i]
11113468e90cSJohn Marino 			      : ((*srccap == 'k')
11123468e90cSJohn Marino 				 ? 0
11133468e90cSJohn Marino 				 : has_params(srccap)));
11145f4613f2SJohn Marino 		char *cv = _nc_infotocap(name, srccap, params);
11155f4613f2SJohn Marino 
11165f4613f2SJohn Marino 		if (cv == 0) {
11175f4613f2SJohn Marino 		    if (outform == F_TCONVERR) {
11183468e90cSJohn Marino 			_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
11193468e90cSJohn Marino 				    "%s=!!! %s WILL NOT CONVERT !!!",
11205f4613f2SJohn Marino 				    name, srccap);
1121*32bb5217SDaniel Fojt 			WRAP_CONCAT;
11225f4613f2SJohn Marino 		    } else if (suppress_untranslatable) {
11235f4613f2SJohn Marino 			continue;
11245f4613f2SJohn Marino 		    } else {
11255f4613f2SJohn Marino 			char *s = srccap, *d = buffer;
1126*32bb5217SDaniel Fojt 			int need = 3 + (int) strlen(name);
11275f4613f2SJohn Marino 			while ((*d = *s++) != 0) {
1128*32bb5217SDaniel Fojt 			    if ((d - buffer + 1) >= (int) sizeof(buffer)) {
1129*32bb5217SDaniel Fojt 				fprintf(stderr,
1130*32bb5217SDaniel Fojt 					"%s: value for %s is too long\n",
1131*32bb5217SDaniel Fojt 					_nc_progname,
1132*32bb5217SDaniel Fojt 					name);
1133*32bb5217SDaniel Fojt 				*d = '\0';
1134*32bb5217SDaniel Fojt 				break;
1135*32bb5217SDaniel Fojt 			    }
11365f4613f2SJohn Marino 			    if (*d == ':') {
11375f4613f2SJohn Marino 				*d++ = '\\';
11385f4613f2SJohn Marino 				*d = ':';
11395f4613f2SJohn Marino 			    } else if (*d == '\\') {
1140*32bb5217SDaniel Fojt 				if ((*++d = *s++) == '\0')
1141*32bb5217SDaniel Fojt 				    break;
11425f4613f2SJohn Marino 			    }
11435f4613f2SJohn Marino 			    d++;
1144*32bb5217SDaniel Fojt 			    *d = '\0';
11455f4613f2SJohn Marino 			}
1146*32bb5217SDaniel Fojt 			need += (int) (d - buffer);
1147*32bb5217SDaniel Fojt 			wrap_concat("..", need, w1ST | wERR);
1148*32bb5217SDaniel Fojt 			need -= 2;
1149*32bb5217SDaniel Fojt 			wrap_concat(name, need, wOFF | wERR);
1150*32bb5217SDaniel Fojt 			need -= (int) strlen(name);
1151*32bb5217SDaniel Fojt 			wrap_concat("=", need, w2ND | wERR);
1152*32bb5217SDaniel Fojt 			need -= 1;
1153*32bb5217SDaniel Fojt 			wrap_concat(buffer, need, wEND | wERR);
1154*32bb5217SDaniel Fojt 			outcount = TRUE;
11555f4613f2SJohn Marino 		    }
11565f4613f2SJohn Marino 		} else {
1157*32bb5217SDaniel Fojt 		    wrap_concat3(name, "=", cv);
11585f4613f2SJohn Marino 		}
11595f4613f2SJohn Marino 		len += (int) strlen(capability) + 1;
11605f4613f2SJohn Marino 	    } else {
11615f4613f2SJohn Marino 		char *src = _nc_tic_expand(capability,
11625f4613f2SJohn Marino 					   outform == F_TERMINFO, numbers);
11635f4613f2SJohn Marino 
11645f4613f2SJohn Marino 		strcpy_DYN(&tmpbuf, 0);
11655f4613f2SJohn Marino 		strcpy_DYN(&tmpbuf, name);
11665f4613f2SJohn Marino 		strcpy_DYN(&tmpbuf, "=");
11675f4613f2SJohn Marino 		if (pretty
11685f4613f2SJohn Marino 		    && (outform == F_TERMINFO
11695f4613f2SJohn Marino 			|| outform == F_VARIABLE)) {
11703468e90cSJohn Marino 		    fmt_complex(tterm, name, src, 1);
11715f4613f2SJohn Marino 		} else {
11725f4613f2SJohn Marino 		    strcpy_DYN(&tmpbuf, src);
11735f4613f2SJohn Marino 		}
11745f4613f2SJohn Marino 		len += (int) strlen(capability) + 1;
1175*32bb5217SDaniel Fojt 		WRAP_CONCAT1(tmpbuf.text);
11765f4613f2SJohn Marino 	    }
11775f4613f2SJohn Marino 	}
11785f4613f2SJohn Marino 	/* e.g., trimmed_sgr0 */
1179*32bb5217SDaniel Fojt 	if (VALID_STRING(capability) &&
11803468e90cSJohn Marino 	    capability != tterm->Strings[i])
11815f4613f2SJohn Marino 	    free(capability);
11825f4613f2SJohn Marino     }
11835f4613f2SJohn Marino     len += (int) (num_strings * 2);
11845f4613f2SJohn Marino 
11855f4613f2SJohn Marino     /*
11865f4613f2SJohn Marino      * This piece of code should be an effective inverse of the functions
11875f4613f2SJohn Marino      * postprocess_terminfo() and postprocess_terminfo() in parse_entry.c.
11885f4613f2SJohn Marino      * Much more work should be done on this to support dumping termcaps.
11895f4613f2SJohn Marino      */
11905f4613f2SJohn Marino     if (tversion == V_HPUX) {
11915f4613f2SJohn Marino 	if (VALID_STRING(memory_lock)) {
11923468e90cSJohn Marino 	    _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
11933468e90cSJohn Marino 			"meml=%s", memory_lock);
11945f4613f2SJohn Marino 	    WRAP_CONCAT;
11955f4613f2SJohn Marino 	}
11965f4613f2SJohn Marino 	if (VALID_STRING(memory_unlock)) {
11973468e90cSJohn Marino 	    _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
11983468e90cSJohn Marino 			"memu=%s", memory_unlock);
11995f4613f2SJohn Marino 	    WRAP_CONCAT;
12005f4613f2SJohn Marino 	}
12015f4613f2SJohn Marino     } else if (tversion == V_AIX) {
12025f4613f2SJohn Marino 	if (VALID_STRING(acs_chars)) {
12035f4613f2SJohn Marino 	    bool box_ok = TRUE;
12045f4613f2SJohn Marino 	    const char *acstrans = "lqkxjmwuvtn";
12055f4613f2SJohn Marino 	    const char *cp;
12065f4613f2SJohn Marino 	    char *tp, *sp, boxchars[11];
12075f4613f2SJohn Marino 
12085f4613f2SJohn Marino 	    tp = boxchars;
12095f4613f2SJohn Marino 	    for (cp = acstrans; *cp; cp++) {
12103468e90cSJohn Marino 		sp = (strchr) (acs_chars, *cp);
12115f4613f2SJohn Marino 		if (sp)
12125f4613f2SJohn Marino 		    *tp++ = sp[1];
12135f4613f2SJohn Marino 		else {
12145f4613f2SJohn Marino 		    box_ok = FALSE;
12155f4613f2SJohn Marino 		    break;
12165f4613f2SJohn Marino 		}
12175f4613f2SJohn Marino 	    }
12185f4613f2SJohn Marino 	    tp[0] = '\0';
12195f4613f2SJohn Marino 
12205f4613f2SJohn Marino 	    if (box_ok) {
12213468e90cSJohn Marino 		char *tmp = _nc_tic_expand(boxchars,
12223468e90cSJohn Marino 					   (outform == F_TERMINFO),
12233468e90cSJohn Marino 					   numbers);
12243468e90cSJohn Marino 		_nc_STRCPY(buffer, "box1=", sizeof(buffer));
12253468e90cSJohn Marino 		while (*tmp != '\0') {
12263468e90cSJohn Marino 		    size_t have = strlen(buffer);
12273468e90cSJohn Marino 		    size_t next = strlen(tmp);
12283468e90cSJohn Marino 		    size_t want = have + next + 1;
12293468e90cSJohn Marino 		    size_t last = next;
12303468e90cSJohn Marino 		    char save = '\0';
12313468e90cSJohn Marino 
12323468e90cSJohn Marino 		    /*
12333468e90cSJohn Marino 		     * If the expanded string is too long for the buffer,
12343468e90cSJohn Marino 		     * chop it off and save the location where we chopped it.
12353468e90cSJohn Marino 		     */
12363468e90cSJohn Marino 		    if (want >= sizeof(buffer)) {
12373468e90cSJohn Marino 			save = tmp[last];
12383468e90cSJohn Marino 			tmp[last] = '\0';
12393468e90cSJohn Marino 		    }
12403468e90cSJohn Marino 		    _nc_STRCAT(buffer, tmp, sizeof(buffer));
12413468e90cSJohn Marino 
12423468e90cSJohn Marino 		    /*
12433468e90cSJohn Marino 		     * If we chopped the buffer, replace the missing piece and
12443468e90cSJohn Marino 		     * shift everything to append the remainder.
12453468e90cSJohn Marino 		     */
12463468e90cSJohn Marino 		    if (save != '\0') {
12473468e90cSJohn Marino 			next = 0;
12483468e90cSJohn Marino 			tmp[last] = save;
12493468e90cSJohn Marino 			while ((tmp[next] = tmp[last + next]) != '\0') {
12503468e90cSJohn Marino 			    ++next;
12513468e90cSJohn Marino 			}
12523468e90cSJohn Marino 		    } else {
12533468e90cSJohn Marino 			break;
12543468e90cSJohn Marino 		    }
12553468e90cSJohn Marino 		}
12565f4613f2SJohn Marino 		WRAP_CONCAT;
12575f4613f2SJohn Marino 	    }
12585f4613f2SJohn Marino 	}
12595f4613f2SJohn Marino     }
12605f4613f2SJohn Marino 
12615f4613f2SJohn Marino     /*
12625f4613f2SJohn Marino      * kludge: trim off trailer to avoid an extra blank line
12635f4613f2SJohn Marino      * in infocmp -u output when there are no string differences
12645f4613f2SJohn Marino      */
12655f4613f2SJohn Marino     if (outcount) {
12665f4613f2SJohn Marino 	bool trimmed = FALSE;
12673468e90cSJohn Marino 	j = (PredIdx) outbuf.used;
1268*32bb5217SDaniel Fojt 	if (wrapped && did_wrap) {
1269*32bb5217SDaniel Fojt 	    /* EMPTY */ ;
1270*32bb5217SDaniel Fojt 	} else if (j >= 2
12715f4613f2SJohn Marino 		   && outbuf.text[j - 1] == '\t'
12725f4613f2SJohn Marino 		   && outbuf.text[j - 2] == '\n') {
12735f4613f2SJohn Marino 	    outbuf.used -= 2;
12745f4613f2SJohn Marino 	    trimmed = TRUE;
12755f4613f2SJohn Marino 	} else if (j >= 4
12765f4613f2SJohn Marino 		   && outbuf.text[j - 1] == ':'
12775f4613f2SJohn Marino 		   && outbuf.text[j - 2] == '\t'
12785f4613f2SJohn Marino 		   && outbuf.text[j - 3] == '\n'
12795f4613f2SJohn Marino 		   && outbuf.text[j - 4] == '\\') {
12805f4613f2SJohn Marino 	    outbuf.used -= 4;
12815f4613f2SJohn Marino 	    trimmed = TRUE;
12825f4613f2SJohn Marino 	}
12835f4613f2SJohn Marino 	if (trimmed) {
12845f4613f2SJohn Marino 	    outbuf.text[outbuf.used] = '\0';
12855f4613f2SJohn Marino 	    column = oldcol;
12865f4613f2SJohn Marino 	    strcpy_DYN(&outbuf, " ");
12875f4613f2SJohn Marino 	}
12885f4613f2SJohn Marino     }
12895f4613f2SJohn Marino #if 0
12905f4613f2SJohn Marino     fprintf(stderr, "num_bools = %d\n", num_bools);
12915f4613f2SJohn Marino     fprintf(stderr, "num_values = %d\n", num_values);
12925f4613f2SJohn Marino     fprintf(stderr, "num_strings = %d\n", num_strings);
12935f4613f2SJohn Marino     fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
12945f4613f2SJohn Marino 	    tterm->term_names, len, outbuf.used, outbuf.text);
12955f4613f2SJohn Marino #endif
12965f4613f2SJohn Marino     /*
12975f4613f2SJohn Marino      * Here's where we use infodump to trigger a more stringent length check
12985f4613f2SJohn Marino      * for termcap-translation purposes.
12995f4613f2SJohn Marino      * Return the length of the raw entry, without tc= expansions,
13005f4613f2SJohn Marino      * It gives an idea of which entries are deadly to even *scan past*,
13015f4613f2SJohn Marino      * as opposed to *use*.
13025f4613f2SJohn Marino      */
13035f4613f2SJohn Marino     return (infodump ? len : (int) termcap_length(outbuf.text));
13045f4613f2SJohn Marino }
13055f4613f2SJohn Marino 
13065f4613f2SJohn Marino static bool
kill_string(TERMTYPE2 * tterm,char * cap)1307*32bb5217SDaniel Fojt kill_string(TERMTYPE2 *tterm, char *cap)
13085f4613f2SJohn Marino {
13095f4613f2SJohn Marino     unsigned n;
13105f4613f2SJohn Marino     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
13115f4613f2SJohn Marino 	if (cap == tterm->Strings[n]) {
13125f4613f2SJohn Marino 	    tterm->Strings[n] = ABSENT_STRING;
13135f4613f2SJohn Marino 	    return TRUE;
13145f4613f2SJohn Marino 	}
13155f4613f2SJohn Marino     }
13165f4613f2SJohn Marino     return FALSE;
13175f4613f2SJohn Marino }
13185f4613f2SJohn Marino 
13195f4613f2SJohn Marino static char *
find_string(TERMTYPE2 * tterm,char * name)1320*32bb5217SDaniel Fojt find_string(TERMTYPE2 *tterm, char *name)
13215f4613f2SJohn Marino {
13225f4613f2SJohn Marino     PredIdx n;
13235f4613f2SJohn Marino     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
13245f4613f2SJohn Marino 	if (version_filter(STRING, n)
13255f4613f2SJohn Marino 	    && !strcmp(name, strnames[n])) {
13265f4613f2SJohn Marino 	    char *cap = tterm->Strings[n];
13275f4613f2SJohn Marino 	    if (VALID_STRING(cap)) {
13285f4613f2SJohn Marino 		return cap;
13295f4613f2SJohn Marino 	    }
13305f4613f2SJohn Marino 	    break;
13315f4613f2SJohn Marino 	}
13325f4613f2SJohn Marino     }
13335f4613f2SJohn Marino     return ABSENT_STRING;
13345f4613f2SJohn Marino }
13355f4613f2SJohn Marino 
13365f4613f2SJohn Marino /*
13375f4613f2SJohn Marino  * This is used to remove function-key labels from a termcap entry to
13385f4613f2SJohn Marino  * make it smaller.
13395f4613f2SJohn Marino  */
13405f4613f2SJohn Marino static int
kill_labels(TERMTYPE2 * tterm,int target)1341*32bb5217SDaniel Fojt kill_labels(TERMTYPE2 *tterm, int target)
13425f4613f2SJohn Marino {
13435f4613f2SJohn Marino     int n;
13445f4613f2SJohn Marino     int result = 0;
13455f4613f2SJohn Marino     char *cap;
13465f4613f2SJohn Marino     char name[10];
13475f4613f2SJohn Marino 
13485f4613f2SJohn Marino     for (n = 0; n <= 10; ++n) {
13493468e90cSJohn Marino 	_nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "lf%d", n);
1350*32bb5217SDaniel Fojt 	cap = find_string(tterm, name);
1351*32bb5217SDaniel Fojt 	if (VALID_STRING(cap)
13525f4613f2SJohn Marino 	    && kill_string(tterm, cap)) {
13535f4613f2SJohn Marino 	    target -= (int) (strlen(cap) + 5);
13545f4613f2SJohn Marino 	    ++result;
13555f4613f2SJohn Marino 	    if (target < 0)
13565f4613f2SJohn Marino 		break;
13575f4613f2SJohn Marino 	}
13585f4613f2SJohn Marino     }
13595f4613f2SJohn Marino     return result;
13605f4613f2SJohn Marino }
13615f4613f2SJohn Marino 
13625f4613f2SJohn Marino /*
13635f4613f2SJohn Marino  * This is used to remove function-key definitions from a termcap entry to
13645f4613f2SJohn Marino  * make it smaller.
13655f4613f2SJohn Marino  */
13665f4613f2SJohn Marino static int
kill_fkeys(TERMTYPE2 * tterm,int target)1367*32bb5217SDaniel Fojt kill_fkeys(TERMTYPE2 *tterm, int target)
13685f4613f2SJohn Marino {
13695f4613f2SJohn Marino     int n;
13705f4613f2SJohn Marino     int result = 0;
13715f4613f2SJohn Marino     char *cap;
13725f4613f2SJohn Marino     char name[10];
13735f4613f2SJohn Marino 
13745f4613f2SJohn Marino     for (n = 60; n >= 0; --n) {
13753468e90cSJohn Marino 	_nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "kf%d", n);
1376*32bb5217SDaniel Fojt 	cap = find_string(tterm, name);
1377*32bb5217SDaniel Fojt 	if (VALID_STRING(cap)
13785f4613f2SJohn Marino 	    && kill_string(tterm, cap)) {
13795f4613f2SJohn Marino 	    target -= (int) (strlen(cap) + 5);
13805f4613f2SJohn Marino 	    ++result;
13815f4613f2SJohn Marino 	    if (target < 0)
13825f4613f2SJohn Marino 		break;
13835f4613f2SJohn Marino 	}
13845f4613f2SJohn Marino     }
13855f4613f2SJohn Marino     return result;
13865f4613f2SJohn Marino }
13875f4613f2SJohn Marino 
13885f4613f2SJohn Marino /*
13895f4613f2SJohn Marino  * Check if the given acsc string is a 1-1 mapping, i.e., just-like-vt100.
13905f4613f2SJohn Marino  * Also, since this is for termcap, we only care about the line-drawing map.
13915f4613f2SJohn Marino  */
13925f4613f2SJohn Marino #define isLine(c) (strchr("lmkjtuvwqxn", c) != 0)
13935f4613f2SJohn Marino 
13945f4613f2SJohn Marino static bool
one_one_mapping(const char * mapping)13955f4613f2SJohn Marino one_one_mapping(const char *mapping)
13965f4613f2SJohn Marino {
13975f4613f2SJohn Marino     bool result = TRUE;
13985f4613f2SJohn Marino 
1399*32bb5217SDaniel Fojt     if (VALID_STRING(mapping)) {
14005f4613f2SJohn Marino 	int n = 0;
1401*32bb5217SDaniel Fojt 	while (mapping[n] != '\0' && mapping[n + 1] != '\0') {
14025f4613f2SJohn Marino 	    if (isLine(mapping[n]) &&
14035f4613f2SJohn Marino 		mapping[n] != mapping[n + 1]) {
14045f4613f2SJohn Marino 		result = FALSE;
14055f4613f2SJohn Marino 		break;
14065f4613f2SJohn Marino 	    }
14075f4613f2SJohn Marino 	    n += 2;
14085f4613f2SJohn Marino 	}
14095f4613f2SJohn Marino     }
14105f4613f2SJohn Marino     return result;
14115f4613f2SJohn Marino }
14125f4613f2SJohn Marino 
14135f4613f2SJohn Marino #define FMT_ENTRY() \
14145f4613f2SJohn Marino 		fmt_entry(tterm, pred, \
14155f4613f2SJohn Marino 			0, \
14165f4613f2SJohn Marino 			suppress_untranslatable, \
14175f4613f2SJohn Marino 			infodump, numbers)
14185f4613f2SJohn Marino 
14195f4613f2SJohn Marino #define SHOW_WHY PRINTF
14205f4613f2SJohn Marino 
14215f4613f2SJohn Marino static bool
purged_acs(TERMTYPE2 * tterm)1422*32bb5217SDaniel Fojt purged_acs(TERMTYPE2 *tterm)
14235f4613f2SJohn Marino {
14245f4613f2SJohn Marino     bool result = FALSE;
14255f4613f2SJohn Marino 
14265f4613f2SJohn Marino     if (VALID_STRING(acs_chars)) {
14275f4613f2SJohn Marino 	if (!one_one_mapping(acs_chars)) {
14285f4613f2SJohn Marino 	    enter_alt_charset_mode = ABSENT_STRING;
14295f4613f2SJohn Marino 	    exit_alt_charset_mode = ABSENT_STRING;
14305f4613f2SJohn Marino 	    SHOW_WHY("# (rmacs/smacs removed for consistency)\n");
14315f4613f2SJohn Marino 	}
14325f4613f2SJohn Marino 	result = TRUE;
14335f4613f2SJohn Marino     }
14345f4613f2SJohn Marino     return result;
14355f4613f2SJohn Marino }
14365f4613f2SJohn Marino 
14373468e90cSJohn Marino static void
encode_b64(char * target,char * source,unsigned state,int * saved)14383468e90cSJohn Marino encode_b64(char *target, char *source, unsigned state, int *saved)
14393468e90cSJohn Marino {
14403468e90cSJohn Marino     /* RFC-4648 */
14413468e90cSJohn Marino     static const char data[] =
14423468e90cSJohn Marino     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
14433468e90cSJohn Marino     "abcdefghijklmnopqrstuvwxyz"
14443468e90cSJohn Marino     "0123456789" "-_";
14453468e90cSJohn Marino     int ch = UChar(source[state]);
14463468e90cSJohn Marino 
14473468e90cSJohn Marino     switch (state % 3) {
14483468e90cSJohn Marino     case 0:
1449*32bb5217SDaniel Fojt 	*target++ = data[(ch >> 2) & 077];
1450*32bb5217SDaniel Fojt 	*saved = (ch << 4);
14513468e90cSJohn Marino 	break;
14523468e90cSJohn Marino     case 1:
1453*32bb5217SDaniel Fojt 	*target++ = data[((ch >> 4) | *saved) & 077];
1454*32bb5217SDaniel Fojt 	*saved = (ch << 2);
14553468e90cSJohn Marino 	break;
14563468e90cSJohn Marino     case 2:
1457*32bb5217SDaniel Fojt 	*target++ = data[((ch >> 6) | *saved) & 077];
1458*32bb5217SDaniel Fojt 	*target++ = data[ch & 077];
14593468e90cSJohn Marino 	*saved = 0;
14603468e90cSJohn Marino 	break;
14613468e90cSJohn Marino     }
14623468e90cSJohn Marino     *target = '\0';
14633468e90cSJohn Marino }
14643468e90cSJohn Marino 
14655f4613f2SJohn Marino /*
14665f4613f2SJohn Marino  * Dump a single entry.
14675f4613f2SJohn Marino  */
14685f4613f2SJohn Marino void
dump_entry(TERMTYPE2 * tterm,int suppress_untranslatable,int limited,int numbers,PredFunc pred)1469*32bb5217SDaniel Fojt dump_entry(TERMTYPE2 *tterm,
14703468e90cSJohn Marino 	   int suppress_untranslatable,
14713468e90cSJohn Marino 	   int limited,
14725f4613f2SJohn Marino 	   int numbers,
14735f4613f2SJohn Marino 	   PredFunc pred)
14745f4613f2SJohn Marino {
1475*32bb5217SDaniel Fojt     TERMTYPE2 save_tterm;
14765f4613f2SJohn Marino     int len, critlen;
14775f4613f2SJohn Marino     const char *legend;
14785f4613f2SJohn Marino     bool infodump;
14795f4613f2SJohn Marino 
14803468e90cSJohn Marino     if (quickdump) {
14813468e90cSJohn Marino 	char bigbuf[65536];
14823468e90cSJohn Marino 	unsigned n;
14833468e90cSJohn Marino 	unsigned offset = 0;
14843468e90cSJohn Marino 	separator = "";
14853468e90cSJohn Marino 	trailer = "\n";
14863468e90cSJohn Marino 	indent = 0;
14873468e90cSJohn Marino 	if (_nc_write_object(tterm, bigbuf, &offset, sizeof(bigbuf)) == OK) {
14883468e90cSJohn Marino 	    char numbuf[80];
14893468e90cSJohn Marino 	    if (quickdump & 1) {
14903468e90cSJohn Marino 		if (outbuf.used)
1491*32bb5217SDaniel Fojt 		    wrap_concat1("\n");
1492*32bb5217SDaniel Fojt 		wrap_concat1("hex:");
14933468e90cSJohn Marino 		for (n = 0; n < offset; ++n) {
1494*32bb5217SDaniel Fojt 		    _nc_SPRINTF(numbuf, _nc_SLIMIT(sizeof(numbuf))
1495*32bb5217SDaniel Fojt 				"%02X", UChar(bigbuf[n]));
1496*32bb5217SDaniel Fojt 		    wrap_concat1(numbuf);
14973468e90cSJohn Marino 		}
14983468e90cSJohn Marino 	    }
14993468e90cSJohn Marino 	    if (quickdump & 2) {
1500*32bb5217SDaniel Fojt 		static char padding[] =
1501*32bb5217SDaniel Fojt 		{0, 0};
15023468e90cSJohn Marino 		int value = 0;
15033468e90cSJohn Marino 		if (outbuf.used)
1504*32bb5217SDaniel Fojt 		    wrap_concat1("\n");
1505*32bb5217SDaniel Fojt 		wrap_concat1("b64:");
15063468e90cSJohn Marino 		for (n = 0; n < offset; ++n) {
15073468e90cSJohn Marino 		    encode_b64(numbuf, bigbuf, n, &value);
1508*32bb5217SDaniel Fojt 		    wrap_concat1(numbuf);
15093468e90cSJohn Marino 		}
15103468e90cSJohn Marino 		switch (n % 3) {
15113468e90cSJohn Marino 		case 0:
15123468e90cSJohn Marino 		    break;
15133468e90cSJohn Marino 		case 1:
1514*32bb5217SDaniel Fojt 		    encode_b64(numbuf, padding, 1, &value);
1515*32bb5217SDaniel Fojt 		    wrap_concat1(numbuf);
1516*32bb5217SDaniel Fojt 		    wrap_concat1("==");
15173468e90cSJohn Marino 		    break;
15183468e90cSJohn Marino 		case 2:
1519*32bb5217SDaniel Fojt 		    encode_b64(numbuf, padding, 1, &value);
1520*32bb5217SDaniel Fojt 		    wrap_concat1(numbuf);
1521*32bb5217SDaniel Fojt 		    wrap_concat1("=");
15223468e90cSJohn Marino 		    break;
15233468e90cSJohn Marino 		}
15243468e90cSJohn Marino 	    }
15253468e90cSJohn Marino 	}
15263468e90cSJohn Marino 	return;
15273468e90cSJohn Marino     }
15283468e90cSJohn Marino 
1529*32bb5217SDaniel Fojt     if (TcOutput()) {
15305f4613f2SJohn Marino 	critlen = MAX_TERMCAP_LENGTH;
15315f4613f2SJohn Marino 	legend = "older termcap";
15325f4613f2SJohn Marino 	infodump = FALSE;
15335f4613f2SJohn Marino 	set_obsolete_termcaps(tterm);
15345f4613f2SJohn Marino     } else {
15355f4613f2SJohn Marino 	critlen = MAX_TERMINFO_LENGTH;
15365f4613f2SJohn Marino 	legend = "terminfo";
15375f4613f2SJohn Marino 	infodump = TRUE;
15385f4613f2SJohn Marino     }
15395f4613f2SJohn Marino 
15405f4613f2SJohn Marino     save_sgr = set_attributes;
15415f4613f2SJohn Marino 
15425f4613f2SJohn Marino     if ((FMT_ENTRY() > critlen)
15435f4613f2SJohn Marino 	&& limited) {
15445f4613f2SJohn Marino 
15455f4613f2SJohn Marino 	save_tterm = *tterm;
15465f4613f2SJohn Marino 	if (!suppress_untranslatable) {
15475f4613f2SJohn Marino 	    SHOW_WHY("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
15485f4613f2SJohn Marino 		     critlen);
15495f4613f2SJohn Marino 	    suppress_untranslatable = TRUE;
15505f4613f2SJohn Marino 	}
15515f4613f2SJohn Marino 	if (FMT_ENTRY() > critlen) {
15525f4613f2SJohn Marino 	    /*
15535f4613f2SJohn Marino 	     * We pick on sgr because it's a nice long string capability that
15545f4613f2SJohn Marino 	     * is really just an optimization hack.  Another good candidate is
15555f4613f2SJohn Marino 	     * acsc since it is both long and unused by BSD termcap.
15565f4613f2SJohn Marino 	     */
15575f4613f2SJohn Marino 	    bool changed = FALSE;
15585f4613f2SJohn Marino 
15595f4613f2SJohn Marino #if NCURSES_XNAMES
15605f4613f2SJohn Marino 	    /*
15615f4613f2SJohn Marino 	     * Extended names are most likely function-key definitions.  Drop
15625f4613f2SJohn Marino 	     * those first.
15635f4613f2SJohn Marino 	     */
15645f4613f2SJohn Marino 	    unsigned n;
15655f4613f2SJohn Marino 	    for (n = STRCOUNT; n < NUM_STRINGS(tterm); n++) {
15663468e90cSJohn Marino 		const char *name = ExtStrname(tterm, (int) n, strnames);
15675f4613f2SJohn Marino 
15685f4613f2SJohn Marino 		if (VALID_STRING(tterm->Strings[n])) {
15695f4613f2SJohn Marino 		    set_attributes = ABSENT_STRING;
15705f4613f2SJohn Marino 		    /* we remove long names anyway - only report the short */
15715f4613f2SJohn Marino 		    if (strlen(name) <= 2) {
15725f4613f2SJohn Marino 			SHOW_WHY("# (%s removed to fit entry within %d bytes)\n",
15735f4613f2SJohn Marino 				 name,
15745f4613f2SJohn Marino 				 critlen);
15755f4613f2SJohn Marino 		    }
15765f4613f2SJohn Marino 		    changed = TRUE;
15775f4613f2SJohn Marino 		    if (FMT_ENTRY() <= critlen)
15785f4613f2SJohn Marino 			break;
15795f4613f2SJohn Marino 		}
15805f4613f2SJohn Marino 	    }
15815f4613f2SJohn Marino #endif
15825f4613f2SJohn Marino 	    if (VALID_STRING(set_attributes)) {
15835f4613f2SJohn Marino 		set_attributes = ABSENT_STRING;
15845f4613f2SJohn Marino 		SHOW_WHY("# (sgr removed to fit entry within %d bytes)\n",
15855f4613f2SJohn Marino 			 critlen);
15865f4613f2SJohn Marino 		changed = TRUE;
15875f4613f2SJohn Marino 	    }
15885f4613f2SJohn Marino 	    if (!changed || (FMT_ENTRY() > critlen)) {
15895f4613f2SJohn Marino 		if (purged_acs(tterm)) {
15905f4613f2SJohn Marino 		    acs_chars = ABSENT_STRING;
15915f4613f2SJohn Marino 		    SHOW_WHY("# (acsc removed to fit entry within %d bytes)\n",
15925f4613f2SJohn Marino 			     critlen);
15935f4613f2SJohn Marino 		    changed = TRUE;
15945f4613f2SJohn Marino 		}
15955f4613f2SJohn Marino 	    }
15965f4613f2SJohn Marino 	    if (!changed || (FMT_ENTRY() > critlen)) {
15975f4613f2SJohn Marino 		int oldversion = tversion;
15985f4613f2SJohn Marino 
15995f4613f2SJohn Marino 		tversion = V_BSD;
16005f4613f2SJohn Marino 		SHOW_WHY("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
16015f4613f2SJohn Marino 			 critlen);
16025f4613f2SJohn Marino 
16035f4613f2SJohn Marino 		len = FMT_ENTRY();
16045f4613f2SJohn Marino 		if (len > critlen
16055f4613f2SJohn Marino 		    && kill_labels(tterm, len - critlen)) {
16065f4613f2SJohn Marino 		    SHOW_WHY("# (some labels capabilities suppressed to fit entry within %d bytes)\n",
16075f4613f2SJohn Marino 			     critlen);
16085f4613f2SJohn Marino 		    len = FMT_ENTRY();
16095f4613f2SJohn Marino 		}
16105f4613f2SJohn Marino 		if (len > critlen
16115f4613f2SJohn Marino 		    && kill_fkeys(tterm, len - critlen)) {
16125f4613f2SJohn Marino 		    SHOW_WHY("# (some function-key capabilities suppressed to fit entry within %d bytes)\n",
16135f4613f2SJohn Marino 			     critlen);
16145f4613f2SJohn Marino 		    len = FMT_ENTRY();
16155f4613f2SJohn Marino 		}
16165f4613f2SJohn Marino 		if (len > critlen) {
16175f4613f2SJohn Marino 		    (void) fprintf(stderr,
1618*32bb5217SDaniel Fojt 				   "%s: %s entry is %d bytes long\n",
1619*32bb5217SDaniel Fojt 				   _nc_progname,
16205f4613f2SJohn Marino 				   _nc_first_name(tterm->term_names),
16215f4613f2SJohn Marino 				   len);
16225f4613f2SJohn Marino 		    SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
16235f4613f2SJohn Marino 			     len, legend);
16245f4613f2SJohn Marino 		}
16255f4613f2SJohn Marino 		tversion = oldversion;
16265f4613f2SJohn Marino 	    }
16275f4613f2SJohn Marino 	    set_attributes = save_sgr;
16285f4613f2SJohn Marino 	    *tterm = save_tterm;
16295f4613f2SJohn Marino 	}
16305f4613f2SJohn Marino     } else if (!version_filter(STRING, STR_IDX(acs_chars))) {
16315f4613f2SJohn Marino 	save_tterm = *tterm;
16325f4613f2SJohn Marino 	if (purged_acs(tterm)) {
16335f4613f2SJohn Marino 	    (void) FMT_ENTRY();
16345f4613f2SJohn Marino 	}
16355f4613f2SJohn Marino 	*tterm = save_tterm;
16365f4613f2SJohn Marino     }
16375f4613f2SJohn Marino }
16385f4613f2SJohn Marino 
16395f4613f2SJohn Marino void
dump_uses(const char * name,bool infodump)16405f4613f2SJohn Marino dump_uses(const char *name, bool infodump)
16415f4613f2SJohn Marino /* dump "use=" clauses in the appropriate format */
16425f4613f2SJohn Marino {
16435f4613f2SJohn Marino     char buffer[MAX_TERMINFO_LENGTH];
16445f4613f2SJohn Marino 
1645*32bb5217SDaniel Fojt     if (TcOutput())
16465f4613f2SJohn Marino 	trim_trailing();
16473468e90cSJohn Marino     _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
16483468e90cSJohn Marino 		"%s%s", infodump ? "use=" : "tc=", name);
1649*32bb5217SDaniel Fojt     wrap_concat1(buffer);
16505f4613f2SJohn Marino }
16515f4613f2SJohn Marino 
16525f4613f2SJohn Marino int
show_entry(void)16535f4613f2SJohn Marino show_entry(void)
16545f4613f2SJohn Marino {
16553468e90cSJohn Marino     /*
16563468e90cSJohn Marino      * Trim any remaining whitespace.
16573468e90cSJohn Marino      */
16583468e90cSJohn Marino     if (outbuf.used != 0) {
1659*32bb5217SDaniel Fojt 	bool infodump = !TcOutput();
16603468e90cSJohn Marino 	char delim = (char) (infodump ? ',' : ':');
16613468e90cSJohn Marino 	int j;
16623468e90cSJohn Marino 
16633468e90cSJohn Marino 	for (j = (int) outbuf.used - 1; j > 0; --j) {
16643468e90cSJohn Marino 	    char ch = outbuf.text[j];
16653468e90cSJohn Marino 	    if (ch == '\n') {
16663468e90cSJohn Marino 		;
16673468e90cSJohn Marino 	    } else if (isspace(UChar(ch))) {
16683468e90cSJohn Marino 		outbuf.used = (size_t) j;
16693468e90cSJohn Marino 	    } else if (!infodump && ch == '\\') {
16703468e90cSJohn Marino 		outbuf.used = (size_t) j;
16713468e90cSJohn Marino 	    } else if (ch == delim && (j == 0 || outbuf.text[j - 1] != '\\')) {
16723468e90cSJohn Marino 		outbuf.used = (size_t) (j + 1);
16733468e90cSJohn Marino 	    } else {
16743468e90cSJohn Marino 		break;
16753468e90cSJohn Marino 	    }
16763468e90cSJohn Marino 	}
16773468e90cSJohn Marino 	outbuf.text[outbuf.used] = '\0';
16783468e90cSJohn Marino     }
16793468e90cSJohn Marino     if (outbuf.text != 0) {
16805f4613f2SJohn Marino 	(void) fputs(outbuf.text, stdout);
16815f4613f2SJohn Marino 	putchar('\n');
16823468e90cSJohn Marino     }
16835f4613f2SJohn Marino     return (int) outbuf.used;
16845f4613f2SJohn Marino }
16855f4613f2SJohn Marino 
16865f4613f2SJohn Marino void
compare_entry(PredHook hook,TERMTYPE2 * tp GCC_UNUSED,bool quiet)16873468e90cSJohn Marino compare_entry(PredHook hook,
1688*32bb5217SDaniel Fojt 	      TERMTYPE2 *tp GCC_UNUSED,
16895f4613f2SJohn Marino 	      bool quiet)
16905f4613f2SJohn Marino /* compare two entries */
16915f4613f2SJohn Marino {
16925f4613f2SJohn Marino     PredIdx i, j;
16935f4613f2SJohn Marino     NCURSES_CONST char *name;
16945f4613f2SJohn Marino 
16955f4613f2SJohn Marino     if (!quiet)
16965f4613f2SJohn Marino 	fputs("    comparing booleans.\n", stdout);
16975f4613f2SJohn Marino     for_each_boolean(j, tp) {
16985f4613f2SJohn Marino 	i = BoolIndirect(j);
16993468e90cSJohn Marino 	name = ExtBoolname(tp, (int) i, bool_names);
17005f4613f2SJohn Marino 
17015f4613f2SJohn Marino 	if (isObsolete(outform, name))
17025f4613f2SJohn Marino 	    continue;
17035f4613f2SJohn Marino 
17045f4613f2SJohn Marino 	(*hook) (CMP_BOOLEAN, i, name);
17055f4613f2SJohn Marino     }
17065f4613f2SJohn Marino 
17075f4613f2SJohn Marino     if (!quiet)
17085f4613f2SJohn Marino 	fputs("    comparing numbers.\n", stdout);
17095f4613f2SJohn Marino     for_each_number(j, tp) {
17105f4613f2SJohn Marino 	i = NumIndirect(j);
17113468e90cSJohn Marino 	name = ExtNumname(tp, (int) i, num_names);
17125f4613f2SJohn Marino 
17135f4613f2SJohn Marino 	if (isObsolete(outform, name))
17145f4613f2SJohn Marino 	    continue;
17155f4613f2SJohn Marino 
17165f4613f2SJohn Marino 	(*hook) (CMP_NUMBER, i, name);
17175f4613f2SJohn Marino     }
17185f4613f2SJohn Marino 
17195f4613f2SJohn Marino     if (!quiet)
17205f4613f2SJohn Marino 	fputs("    comparing strings.\n", stdout);
17215f4613f2SJohn Marino     for_each_string(j, tp) {
17225f4613f2SJohn Marino 	i = StrIndirect(j);
17233468e90cSJohn Marino 	name = ExtStrname(tp, (int) i, str_names);
17245f4613f2SJohn Marino 
17255f4613f2SJohn Marino 	if (isObsolete(outform, name))
17265f4613f2SJohn Marino 	    continue;
17275f4613f2SJohn Marino 
17285f4613f2SJohn Marino 	(*hook) (CMP_STRING, i, name);
17295f4613f2SJohn Marino     }
17305f4613f2SJohn Marino 
17315f4613f2SJohn Marino     /* (void) fputs("    comparing use entries.\n", stdout); */
17325f4613f2SJohn Marino     (*hook) (CMP_USE, 0, "use");
17335f4613f2SJohn Marino 
17345f4613f2SJohn Marino }
17355f4613f2SJohn Marino 
17365f4613f2SJohn Marino #define NOTSET(s)	((s) == 0)
17375f4613f2SJohn Marino 
17385f4613f2SJohn Marino /*
17395f4613f2SJohn Marino  * This bit of legerdemain turns all the terminfo variable names into
17405f4613f2SJohn Marino  * references to locations in the arrays Booleans, Numbers, and Strings ---
17415f4613f2SJohn Marino  * precisely what's needed.
17425f4613f2SJohn Marino  */
17435f4613f2SJohn Marino #undef CUR
17445f4613f2SJohn Marino #define CUR tp->
17455f4613f2SJohn Marino 
17465f4613f2SJohn Marino static void
set_obsolete_termcaps(TERMTYPE2 * tp)1747*32bb5217SDaniel Fojt set_obsolete_termcaps(TERMTYPE2 *tp)
17485f4613f2SJohn Marino {
17495f4613f2SJohn Marino #include "capdefaults.c"
17505f4613f2SJohn Marino }
17515f4613f2SJohn Marino 
17525f4613f2SJohn Marino /*
17535f4613f2SJohn Marino  * Convert an alternate-character-set string to canonical form: sorted and
17545f4613f2SJohn Marino  * unique.
17555f4613f2SJohn Marino  */
17565f4613f2SJohn Marino void
repair_acsc(TERMTYPE2 * tp)1757*32bb5217SDaniel Fojt repair_acsc(TERMTYPE2 *tp)
17585f4613f2SJohn Marino {
17595f4613f2SJohn Marino     if (VALID_STRING(acs_chars)) {
17605f4613f2SJohn Marino 	size_t n, m;
17615f4613f2SJohn Marino 	char mapped[256];
17625f4613f2SJohn Marino 	char extra = 0;
17635f4613f2SJohn Marino 	unsigned source;
17645f4613f2SJohn Marino 	unsigned target;
17655f4613f2SJohn Marino 	bool fix_needed = FALSE;
17665f4613f2SJohn Marino 
17675f4613f2SJohn Marino 	for (n = 0, source = 0; acs_chars[n] != 0; n++) {
17685f4613f2SJohn Marino 	    target = UChar(acs_chars[n]);
17695f4613f2SJohn Marino 	    if (source >= target) {
17705f4613f2SJohn Marino 		fix_needed = TRUE;
17715f4613f2SJohn Marino 		break;
17725f4613f2SJohn Marino 	    }
17735f4613f2SJohn Marino 	    source = target;
17745f4613f2SJohn Marino 	    if (acs_chars[n + 1])
17755f4613f2SJohn Marino 		n++;
17765f4613f2SJohn Marino 	}
17775f4613f2SJohn Marino 	if (fix_needed) {
17785f4613f2SJohn Marino 	    memset(mapped, 0, sizeof(mapped));
17795f4613f2SJohn Marino 	    for (n = 0; acs_chars[n] != 0; n++) {
17805f4613f2SJohn Marino 		source = UChar(acs_chars[n]);
17815f4613f2SJohn Marino 		if ((target = (unsigned char) acs_chars[n + 1]) != 0) {
17825f4613f2SJohn Marino 		    mapped[source] = (char) target;
17835f4613f2SJohn Marino 		    n++;
17845f4613f2SJohn Marino 		} else {
17855f4613f2SJohn Marino 		    extra = (char) source;
17865f4613f2SJohn Marino 		}
17875f4613f2SJohn Marino 	    }
17885f4613f2SJohn Marino 	    for (n = m = 0; n < sizeof(mapped); n++) {
17895f4613f2SJohn Marino 		if (mapped[n]) {
17905f4613f2SJohn Marino 		    acs_chars[m++] = (char) n;
17915f4613f2SJohn Marino 		    acs_chars[m++] = mapped[n];
17925f4613f2SJohn Marino 		}
17935f4613f2SJohn Marino 	    }
17945f4613f2SJohn Marino 	    if (extra)
17955f4613f2SJohn Marino 		acs_chars[m++] = extra;		/* garbage in, garbage out */
17965f4613f2SJohn Marino 	    acs_chars[m] = 0;
17975f4613f2SJohn Marino 	}
17985f4613f2SJohn Marino     }
17995f4613f2SJohn Marino }
1800