[BACK]Return to dump_entry.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tic

Annotation of src/usr.bin/tic/dump_entry.c, Revision 1.21

1.21    ! nicm        1: /*     $OpenBSD: dump_entry.c,v 1.20 2017/05/11 19:13:17 millert Exp $ */
1.2       millert     2:
1.1       millert     3: /****************************************************************************
1.21    ! nicm        4:  * Copyright 2018-2022,2023 Thomas E. Dickey                                *
        !             5:  * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
1.1       millert     6:  *                                                                          *
                      7:  * Permission is hereby granted, free of charge, to any person obtaining a  *
                      8:  * copy of this software and associated documentation files (the            *
                      9:  * "Software"), to deal in the Software without restriction, including      *
                     10:  * without limitation the rights to use, copy, modify, merge, publish,      *
                     11:  * distribute, distribute with modifications, sublicense, and/or sell       *
                     12:  * copies of the Software, and to permit persons to whom the Software is    *
                     13:  * furnished to do so, subject to the following conditions:                 *
                     14:  *                                                                          *
                     15:  * The above copyright notice and this permission notice shall be included  *
                     16:  * in all copies or substantial portions of the Software.                   *
                     17:  *                                                                          *
                     18:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
                     19:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
                     20:  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
                     21:  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
                     22:  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
                     23:  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
                     24:  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
                     25:  *                                                                          *
                     26:  * Except as contained in this notice, the name(s) of the above copyright   *
                     27:  * holders shall not be used in advertising or otherwise to promote the     *
                     28:  * sale, use or other dealings in this Software without prior written       *
                     29:  * authorization.                                                           *
                     30:  ****************************************************************************/
                     31:
                     32: /****************************************************************************
                     33:  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
                     34:  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
1.19      nicm       35:  *     and: Thomas E. Dickey                        1996 on                 *
1.1       millert    36:  ****************************************************************************/
                     37:
                     38: #define __INTERNAL_CAPS_VISIBLE
                     39: #include <progs.priv.h>
                     40:
1.21    ! nicm       41: #include <dump_entry.h>
        !            42: #include <termsort.h>          /* this C file is generated */
1.1       millert    43: #include <parametrized.h>      /* so is this */
                     44:
1.21    ! nicm       45: MODULE_ID("$Id: dump_entry.c,v 1.20 2017/05/11 19:13:17 millert Exp $")
1.11      millert    46:
1.2       millert    47: #define DISCARD(string) string = ABSENT_STRING
1.11      millert    48: #define PRINTF (void) printf
1.21    ! nicm       49: #define WRAPPED 32
1.2       millert    50:
1.19      nicm       51: #define OkIndex(index,array) ((int)(index) >= 0 && (int)(index) < (int) SIZEOF(array))
1.21    ! nicm       52: #define TcOutput() (outform == F_TERMCAP || outform == F_TCONVERR)
1.19      nicm       53:
1.15      millert    54: typedef struct {
                     55:     char *text;
                     56:     size_t used;
                     57:     size_t size;
                     58: } DYNBUF;
                     59:
1.11      millert    60: static int tversion;           /* terminfo version */
                     61: static int outform;            /* output format to use */
                     62: static int sortmode;           /* sort mode to use */
                     63: static int width = 60;         /* max line width for listings */
1.21    ! nicm       64: static int height = 65535;     /* max number of lines for listings */
1.11      millert    65: static int column;             /* current column, limited by 'width' */
                     66: static int oldcol;             /* last value of column before wrap */
                     67: static bool pretty;            /* true if we format if-then-else strings */
1.21    ! nicm       68: static bool wrapped;           /* true if we wrap too-long strings */
        !            69: static bool did_wrap;          /* true if last wrap_concat did wrapping */
        !            70: static bool checking;          /* true if we are checking for tic */
        !            71: static int quickdump;          /* true if we are dumping compiled data */
1.11      millert    72:
1.19      nicm       73: static char *save_sgr;
                     74:
1.15      millert    75: static DYNBUF outbuf;
                     76: static DYNBUF tmpbuf;
1.1       millert    77:
                     78: /* indirection pointers for implementing sort and display modes */
1.19      nicm       79: static const PredIdx *bool_indirect, *num_indirect, *str_indirect;
1.11      millert    80: static NCURSES_CONST char *const *bool_names;
                     81: static NCURSES_CONST char *const *num_names;
                     82: static NCURSES_CONST char *const *str_names;
1.1       millert    83:
1.21    ! nicm       84: static const char *separator = "", *trailer = "";
        !            85: static int indent = 8;
1.1       millert    86:
                     87: /* cover various ports and variants of terminfo */
                     88: #define V_ALLCAPS      0       /* all capabilities (SVr4, XSI, ncurses) */
                     89: #define V_SVR1         1       /* SVR1, Ultrix */
1.21    ! nicm       90: #define V_HPUX         2       /* HP-UX */
1.1       millert    91: #define V_AIX          3       /* AIX */
                     92: #define V_BSD          4       /* BSD */
                     93:
1.9       millert    94: #if NCURSES_XNAMES
                     95: #define OBSOLETE(n) (!_nc_user_definable && (n[0] == 'O' && n[1] == 'T'))
                     96: #else
1.1       millert    97: #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
1.9       millert    98: #endif
                     99:
1.21    ! nicm      100: #define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && (sortmode != S_VARIABLE) && OBSOLETE(n))
1.1       millert   101:
1.4       millert   102: #if NCURSES_XNAMES
                    103: #define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
                    104: #define NumIndirect(j)  ((j >= NUMCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
                    105: #define StrIndirect(j)  ((j >= STRCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
                    106: #else
                    107: #define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
                    108: #define NumIndirect(j)  ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
                    109: #define StrIndirect(j)  ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
                    110: #endif
                    111:
1.21    ! nicm      112: static GCC_NORETURN void
        !           113: failed(const char *s)
        !           114: {
        !           115:     perror(s);
        !           116:     ExitProgram(EXIT_FAILURE);
        !           117: }
        !           118:
1.15      millert   119: static void
                    120: strncpy_DYN(DYNBUF * dst, const char *src, size_t need)
                    121: {
                    122:     size_t want = need + dst->used + 1;
                    123:     if (want > dst->size) {
                    124:        dst->size += (want + 1024);     /* be generous */
                    125:        dst->text = typeRealloc(char, dst->size, dst->text);
1.21    ! nicm      126:        if (dst->text == 0)
        !           127:            failed("strncpy_DYN");
1.15      millert   128:     }
1.21    ! nicm      129:     _nc_STRNCPY(dst->text + dst->used, src, need + 1);
1.15      millert   130:     dst->used += need;
                    131:     dst->text[dst->used] = 0;
                    132: }
                    133:
                    134: static void
                    135: strcpy_DYN(DYNBUF * dst, const char *src)
                    136: {
                    137:     if (src == 0) {
                    138:        dst->used = 0;
                    139:        strcpy_DYN(dst, "");
                    140:     } else {
                    141:        strncpy_DYN(dst, src, strlen(src));
                    142:     }
                    143: }
                    144:
1.1       millert   145: #if NO_LEAKS
1.15      millert   146: static void
                    147: free_DYN(DYNBUF * p)
                    148: {
                    149:     if (p->text != 0)
                    150:        free(p->text);
                    151:     p->text = 0;
                    152:     p->size = 0;
                    153:     p->used = 0;
                    154: }
                    155:
1.11      millert   156: void
                    157: _nc_leaks_dump_entry(void)
1.1       millert   158: {
1.15      millert   159:     free_DYN(&outbuf);
                    160:     free_DYN(&tmpbuf);
1.1       millert   161: }
                    162: #endif
                    163:
1.19      nicm      164: #define NameTrans(check,result) \
1.21    ! nicm      165:            if ((np->nte_index <= OK_ ## check) \
1.19      nicm      166:                && check[np->nte_index]) \
                    167:                return (result[np->nte_index])
                    168:
1.10      millert   169: NCURSES_CONST char *
                    170: nametrans(const char *name)
1.21    ! nicm      171: /* translate a capability name to termcap from terminfo */
1.1       millert   172: {
1.10      millert   173:     const struct name_table_entry *np;
1.1       millert   174:
1.21    ! nicm      175:     if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0) {
1.10      millert   176:        switch (np->nte_type) {
1.1       millert   177:        case BOOLEAN:
1.19      nicm      178:            NameTrans(bool_from_termcap, boolcodes);
1.1       millert   179:            break;
                    180:
                    181:        case NUMBER:
1.19      nicm      182:            NameTrans(num_from_termcap, numcodes);
1.1       millert   183:            break;
                    184:
                    185:        case STRING:
1.19      nicm      186:            NameTrans(str_from_termcap, strcodes);
1.1       millert   187:            break;
                    188:        }
1.21    ! nicm      189:     }
1.1       millert   190:
1.10      millert   191:     return (0);
1.1       millert   192: }
                    193:
1.10      millert   194: void
1.21    ! nicm      195: dump_init(const char *version,
        !           196:          int mode,
        !           197:          int sort,
        !           198:          bool wrap_strings,
        !           199:          int twidth,
        !           200:          int theight,
        !           201:          unsigned traceval,
        !           202:          bool formatted,
        !           203:          bool check,
        !           204:          int quick)
1.1       millert   205: /* set up for entry display */
                    206: {
                    207:     width = twidth;
1.21    ! nicm      208:     height = theight;
1.1       millert   209:     pretty = formatted;
1.21    ! nicm      210:     wrapped = wrap_strings;
        !           211:     checking = check;
        !           212:     quickdump = (quick & 3);
        !           213:
        !           214:     did_wrap = (width <= 0);
1.1       millert   215:
                    216:     /* versions */
                    217:     if (version == 0)
                    218:        tversion = V_ALLCAPS;
                    219:     else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
1.19      nicm      220:             || !strcmp(version, "Ultrix"))
1.1       millert   221:        tversion = V_SVR1;
                    222:     else if (!strcmp(version, "HP"))
                    223:        tversion = V_HPUX;
                    224:     else if (!strcmp(version, "AIX"))
                    225:        tversion = V_AIX;
                    226:     else if (!strcmp(version, "BSD"))
                    227:        tversion = V_BSD;
                    228:     else
                    229:        tversion = V_ALLCAPS;
                    230:
                    231:     /* implement display modes */
1.10      millert   232:     switch (outform = mode) {
1.1       millert   233:     case F_LITERAL:
                    234:     case F_TERMINFO:
                    235:        bool_names = boolnames;
                    236:        num_names = numnames;
                    237:        str_names = strnames;
1.21    ! nicm      238:        separator = (twidth > 0 && theight > 1) ? ", " : ",";
1.1       millert   239:        trailer = "\n\t";
                    240:        break;
                    241:
                    242:     case F_VARIABLE:
                    243:        bool_names = boolfnames;
                    244:        num_names = numfnames;
                    245:        str_names = strfnames;
1.21    ! nicm      246:        separator = (twidth > 0 && theight > 1) ? ", " : ",";
1.1       millert   247:        trailer = "\n\t";
                    248:        break;
                    249:
                    250:     case F_TERMCAP:
                    251:     case F_TCONVERR:
                    252:        bool_names = boolcodes;
                    253:        num_names = numcodes;
                    254:        str_names = strcodes;
                    255:        separator = ":";
                    256:        trailer = "\\\n\t:";
                    257:        break;
                    258:     }
1.21    ! nicm      259:     indent = 8;
1.1       millert   260:
                    261:     /* implement sort modes */
1.10      millert   262:     switch (sortmode = sort) {
1.1       millert   263:     case S_NOSORT:
                    264:        if (traceval)
                    265:            (void) fprintf(stderr,
1.19      nicm      266:                           "%s: sorting by term structure order\n", _nc_progname);
1.1       millert   267:        break;
                    268:
                    269:     case S_TERMINFO:
                    270:        if (traceval)
                    271:            (void) fprintf(stderr,
1.19      nicm      272:                           "%s: sorting by terminfo name order\n", _nc_progname);
1.1       millert   273:        bool_indirect = bool_terminfo_sort;
                    274:        num_indirect = num_terminfo_sort;
                    275:        str_indirect = str_terminfo_sort;
                    276:        break;
                    277:
                    278:     case S_VARIABLE:
                    279:        if (traceval)
                    280:            (void) fprintf(stderr,
1.19      nicm      281:                           "%s: sorting by C variable order\n", _nc_progname);
1.1       millert   282:        bool_indirect = bool_variable_sort;
                    283:        num_indirect = num_variable_sort;
                    284:        str_indirect = str_variable_sort;
                    285:        break;
                    286:
                    287:     case S_TERMCAP:
                    288:        if (traceval)
                    289:            (void) fprintf(stderr,
1.19      nicm      290:                           "%s: sorting by termcap name order\n", _nc_progname);
1.1       millert   291:        bool_indirect = bool_termcap_sort;
                    292:        num_indirect = num_termcap_sort;
                    293:        str_indirect = str_termcap_sort;
                    294:        break;
                    295:     }
                    296:
                    297:     if (traceval)
                    298:        (void) fprintf(stderr,
1.19      nicm      299:                       "%s: width = %d, tversion = %d, outform = %d\n",
                    300:                       _nc_progname, width, tversion, outform);
1.1       millert   301: }
                    302:
1.21    ! nicm      303: static TERMTYPE2 *cur_type;
1.1       millert   304:
1.10      millert   305: static int
1.19      nicm      306: dump_predicate(PredType type, PredIdx idx)
1.1       millert   307: /* predicate function to use for ordinary decompilation */
                    308: {
1.10      millert   309:     switch (type) {
                    310:     case BOOLEAN:
                    311:        return (cur_type->Booleans[idx] == FALSE)
                    312:            ? FAIL : cur_type->Booleans[idx];
1.1       millert   313:
1.10      millert   314:     case NUMBER:
                    315:        return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
                    316:            ? FAIL : cur_type->Numbers[idx];
1.1       millert   317:
1.10      millert   318:     case STRING:
                    319:        return (cur_type->Strings[idx] != ABSENT_STRING)
                    320:            ? (int) TRUE : FAIL;
                    321:     }
1.1       millert   322:
1.10      millert   323:     return (FALSE);            /* pacify compiler */
1.1       millert   324: }
                    325:
1.21    ! nicm      326: static void set_obsolete_termcaps(TERMTYPE2 *tp);
1.1       millert   327:
                    328: /* is this the index of a function key string? */
1.21    ! nicm      329: #define FNKEY(i) \
        !           330:     (((i) >= STR_IDX(key_f0) && \
        !           331:       (i) <= STR_IDX(key_f9)) || \
        !           332:      ((i) >= STR_IDX(key_f11) && \
        !           333:       (i) <= STR_IDX(key_f63)))
1.1       millert   334:
1.19      nicm      335: /*
                    336:  * If we configure with a different Caps file, the offsets into the arrays
                    337:  * will change.  So we use an address expression.
                    338:  */
                    339: #define BOOL_IDX(name) (PredType) (&(name) - &(CUR Booleans[0]))
                    340: #define NUM_IDX(name)  (PredType) (&(name) - &(CUR Numbers[0]))
                    341: #define STR_IDX(name)  (PredType) (&(name) - &(CUR Strings[0]))
                    342:
1.10      millert   343: static bool
1.19      nicm      344: version_filter(PredType type, PredIdx idx)
1.1       millert   345: /* filter out capabilities we may want to suppress */
                    346: {
1.10      millert   347:     switch (tversion) {
                    348:     case V_ALLCAPS:            /* SVr4, XSI Curses */
                    349:        return (TRUE);
                    350:
                    351:     case V_SVR1:               /* System V Release 1, Ultrix */
                    352:        switch (type) {
1.1       millert   353:        case BOOLEAN:
1.19      nicm      354:            return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
1.1       millert   355:        case NUMBER:
1.19      nicm      356:            return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
1.1       millert   357:        case STRING:
1.19      nicm      358:            return ((idx <= STR_IDX(prtr_non)) ? TRUE : FALSE);
1.1       millert   359:        }
                    360:        break;
                    361:
                    362:     case V_HPUX:               /* Hewlett-Packard */
1.10      millert   363:        switch (type) {
1.1       millert   364:        case BOOLEAN:
1.19      nicm      365:            return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
1.1       millert   366:        case NUMBER:
1.19      nicm      367:            return ((idx <= NUM_IDX(label_width)) ? TRUE : FALSE);
1.1       millert   368:        case STRING:
1.19      nicm      369:            if (idx <= STR_IDX(prtr_non))
1.10      millert   370:                return (TRUE);
1.1       millert   371:            else if (FNKEY(idx))        /* function keys */
1.10      millert   372:                return (TRUE);
1.19      nicm      373:            else if (idx == STR_IDX(plab_norm)
                    374:                     || idx == STR_IDX(label_on)
                    375:                     || idx == STR_IDX(label_off))
1.10      millert   376:                return (TRUE);
1.1       millert   377:            else
1.10      millert   378:                return (FALSE);
1.1       millert   379:        }
                    380:        break;
                    381:
                    382:     case V_AIX:                /* AIX */
1.10      millert   383:        switch (type) {
1.1       millert   384:        case BOOLEAN:
1.19      nicm      385:            return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
1.1       millert   386:        case NUMBER:
1.19      nicm      387:            return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
1.1       millert   388:        case STRING:
1.19      nicm      389:            if (idx <= STR_IDX(prtr_non))
1.10      millert   390:                return (TRUE);
1.1       millert   391:            else if (FNKEY(idx))        /* function keys */
1.10      millert   392:                return (TRUE);
1.1       millert   393:            else
1.10      millert   394:                return (FALSE);
1.1       millert   395:        }
                    396:        break;
                    397:
1.19      nicm      398: #define is_termcap(type) (OkIndex(idx, type##_from_termcap) && \
                    399:                          type##_from_termcap[idx])
                    400:
1.1       millert   401:     case V_BSD:                /* BSD */
1.10      millert   402:        switch (type) {
1.1       millert   403:        case BOOLEAN:
1.19      nicm      404:            return is_termcap(bool);
1.1       millert   405:        case NUMBER:
1.19      nicm      406:            return is_termcap(num);
1.1       millert   407:        case STRING:
1.19      nicm      408:            return is_termcap(str);
1.1       millert   409:        }
                    410:        break;
                    411:     }
                    412:
1.10      millert   413:     return (FALSE);            /* pacify the compiler */
1.1       millert   414: }
                    415:
1.11      millert   416: static void
1.19      nicm      417: trim_trailing(void)
                    418: {
                    419:     while (outbuf.used > 0 && outbuf.text[outbuf.used - 1] == ' ')
                    420:        outbuf.text[--outbuf.used] = '\0';
                    421: }
                    422:
                    423: static void
1.10      millert   424: force_wrap(void)
1.1       millert   425: {
1.10      millert   426:     oldcol = column;
1.19      nicm      427:     trim_trailing();
1.15      millert   428:     strcpy_DYN(&outbuf, trailer);
1.21    ! nicm      429:     column = indent;
        !           430: }
        !           431:
        !           432: static int
        !           433: op_length(const char *src, int offset)
        !           434: {
        !           435:     int result = 0;
        !           436:
        !           437:     if (offset > 0 && src[offset - 1] == '\\') {
        !           438:        result = 0;
        !           439:     } else {
        !           440:        int ch;
        !           441:
        !           442:        result++;               /* for '%' mark */
        !           443:        ch = src[offset + result];
        !           444:        if (TcOutput()) {
        !           445:            if (ch == '>') {
        !           446:                result += 3;
        !           447:            } else if (ch == '+') {
        !           448:                result += 2;
        !           449:            } else {
        !           450:                result++;
        !           451:            }
        !           452:        } else if (ch == '\'') {
        !           453:            result += 3;
        !           454:        } else if (ch == L_CURL[0]) {
        !           455:            int n = result;
        !           456:            while ((ch = src[offset + n]) != '\0') {
        !           457:                if (ch == R_CURL[0]) {
        !           458:                    result = ++n;
        !           459:                    break;
        !           460:                }
        !           461:                n++;
        !           462:            }
        !           463:        } else if (strchr("pPg", ch) != 0) {
        !           464:            result += 2;
        !           465:        } else {
        !           466:            result++;           /* ordinary operator */
        !           467:        }
        !           468:     }
        !           469:     return result;
        !           470: }
        !           471:
        !           472: /*
        !           473:  * When wrapping too-long strings, avoid splitting a backslash sequence, or
        !           474:  * a terminfo '%' operator.  That will leave things a little ragged, but avoids
        !           475:  * a stray backslash at the end of the line, as well as making the result a
        !           476:  * little more readable.
        !           477:  */
        !           478: static int
        !           479: find_split(const char *src, int step, int size)
        !           480: {
        !           481:     int result = size;
        !           482:
        !           483:     if (size > 0) {
        !           484:        /* check if that would split a backslash-sequence */
        !           485:        int mark = size;
        !           486:        int n;
        !           487:
        !           488:        for (n = size - 1; n > 0; --n) {
        !           489:            int ch = UChar(src[step + n]);
        !           490:            if (ch == '\\') {
        !           491:                if (n > 0 && src[step + n - 1] == ch)
        !           492:                    --n;
        !           493:                mark = n;
        !           494:                break;
        !           495:            } else if (!isalnum(ch)) {
        !           496:                break;
        !           497:            }
        !           498:        }
        !           499:        if (mark < size) {
        !           500:            result = mark;
        !           501:        } else {
        !           502:            /* check if that would split a backslash-sequence */
        !           503:            for (n = size - 1; n > 0; --n) {
        !           504:                int ch = UChar(src[step + n]);
        !           505:                if (ch == '%') {
        !           506:                    int need = op_length(src, step + n);
        !           507:                    if ((n + need) > size) {
        !           508:                        mark = n;
        !           509:                    }
        !           510:                    break;
        !           511:                }
        !           512:            }
        !           513:            if (mark < size) {
        !           514:                result = mark;
        !           515:            }
        !           516:        }
        !           517:     }
        !           518:     return result;
1.1       millert   519: }
                    520:
1.21    ! nicm      521: /*
        !           522:  * If we are going to wrap lines, we cannot leave literal spaces because that
        !           523:  * would be ambiguous if we split on that space.
        !           524:  */
        !           525: static char *
        !           526: fill_spaces(const char *src)
        !           527: {
        !           528:     const char *fill = "\\s";
        !           529:     size_t need = strlen(src);
        !           530:     size_t size = strlen(fill);
        !           531:     char *result = 0;
        !           532:     int pass;
        !           533:     size_t s, d;
        !           534:     for (pass = 0; pass < 2; ++pass) {
        !           535:        for (s = d = 0; src[s] != '\0'; ++s) {
        !           536:            if (src[s] == ' ') {
        !           537:                if (pass) {
        !           538:                    _nc_STRCPY(&result[d], fill, need + 1 - d);
        !           539:                    d += size;
        !           540:                } else {
        !           541:                    need += size;
        !           542:                }
        !           543:            } else {
        !           544:                if (pass) {
        !           545:                    result[d++] = src[s];
        !           546:                } else {
        !           547:                    ++d;
        !           548:                }
        !           549:            }
        !           550:        }
        !           551:        if (pass) {
        !           552:            result[d] = '\0';
        !           553:        } else {
        !           554:            result = calloc(need + 1, sizeof(char));
        !           555:            if (result == 0)
        !           556:                failed("fill_spaces");
        !           557:        }
        !           558:     }
        !           559:     return result;
        !           560: }
        !           561:
        !           562: typedef enum {
        !           563:     wOFF = 0
        !           564:     ,w1ST = 1
        !           565:     ,w2ND = 2
        !           566:     ,wEND = 4
        !           567:     ,wERR = 8
        !           568: } WRAPMODE;
        !           569:
        !           570: #define wrap_1ST(mode) ((mode)&w1ST)
        !           571: #define wrap_END(mode) ((mode)&wEND)
        !           572: #define wrap_ERR(mode) ((mode)&wERR)
        !           573:
1.11      millert   574: static void
1.21    ! nicm      575: wrap_concat(const char *src, int need, unsigned mode)
1.1       millert   576: {
1.21    ! nicm      577:     int gaps = (int) strlen(separator);
        !           578:     int want = gaps + need;
1.1       millert   579:
1.21    ! nicm      580:     did_wrap = (width <= 0);
        !           581:     if (wrap_1ST(mode)
        !           582:        && column > indent
        !           583:        && column + want > width) {
1.10      millert   584:        force_wrap();
                    585:     }
1.21    ! nicm      586:     if ((wrap_END(mode) && !wrap_ERR(mode)) &&
        !           587:        wrapped &&
        !           588:        (width >= 0) &&
        !           589:        (column + want) > width) {
        !           590:        int step = 0;
        !           591:        int used = width > WRAPPED ? width : WRAPPED;
        !           592:        int base = 0;
        !           593:        char *p, align[9];
        !           594:        const char *my_t = trailer;
        !           595:        char *fill = fill_spaces(src);
        !           596:        int last = (int) strlen(fill);
        !           597:
        !           598:        need = last;
        !           599:
        !           600:        if (TcOutput())
        !           601:            trailer = "\\\n\t ";
        !           602:
        !           603:        if (!TcOutput() && (p = strchr(fill, '=')) != 0) {
        !           604:            base = (int) (p + 1 - fill);
        !           605:            if (base > 8)
        !           606:                base = 8;
        !           607:            _nc_SPRINTF(align, _nc_SLIMIT(align) "%*s", base, " ");
        !           608:        } else if (column > 8) {
        !           609:            base = column - 8;
        !           610:            if (base > 8)
        !           611:                base = 8;
        !           612:            _nc_SPRINTF(align, _nc_SLIMIT(align) "%*s", base, " ");
        !           613:        } else {
        !           614:            align[base] = '\0';
        !           615:        }
        !           616:        /* "pretty" overrides wrapping if it already split the line */
        !           617:        if (!pretty || strchr(fill, '\n') == 0) {
        !           618:            int tag = 0;
        !           619:
        !           620:            if (TcOutput() && outbuf.used && !wrap_1ST(mode)) {
        !           621:                tag = 3;
        !           622:            }
        !           623:
        !           624:            while ((column + (need + gaps)) > used) {
        !           625:                int size = used - tag;
        !           626:                if (step) {
        !           627:                    strcpy_DYN(&outbuf, align);
        !           628:                    size -= base;
        !           629:                }
        !           630:                if (size > (last - step)) {
        !           631:                    size = (last - step);
        !           632:                }
        !           633:                size = find_split(fill, step, size);
        !           634:                strncpy_DYN(&outbuf, fill + step, (size_t) size);
        !           635:                step += size;
        !           636:                need -= size;
        !           637:                if (need > 0) {
        !           638:                    force_wrap();
        !           639:                    did_wrap = TRUE;
        !           640:                    tag = 0;
        !           641:                }
        !           642:            }
        !           643:        }
        !           644:        if (need > 0) {
        !           645:            if (step)
        !           646:                strcpy_DYN(&outbuf, align);
        !           647:            strcpy_DYN(&outbuf, fill + step);
        !           648:        }
        !           649:        if (wrap_END(mode))
        !           650:            strcpy_DYN(&outbuf, separator);
        !           651:        trailer = my_t;
        !           652:        force_wrap();
        !           653:
        !           654:        free(fill);
        !           655:     } else {
        !           656:        strcpy_DYN(&outbuf, src);
        !           657:        if (wrap_END(mode))
        !           658:            strcpy_DYN(&outbuf, separator);
        !           659:        column += (int) strlen(src);
        !           660:     }
        !           661: }
        !           662:
        !           663: static void
        !           664: wrap_concat1(const char *src)
        !           665: {
        !           666:     int need = (int) strlen(src);
        !           667:     wrap_concat(src, need, w1ST | wEND);
        !           668: }
        !           669:
        !           670: static void
        !           671: wrap_concat3(const char *name, const char *eqls, const char *value)
        !           672: {
        !           673:     int nlen = (int) strlen(name);
        !           674:     int elen = (int) strlen(eqls);
        !           675:     int vlen = (int) strlen(value);
        !           676:
        !           677:     wrap_concat(name, nlen + elen + vlen, w1ST);
        !           678:     wrap_concat(eqls, elen + vlen, w2ND);
        !           679:     wrap_concat(value, vlen, wEND);
1.1       millert   680: }
                    681:
                    682: #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
                    683:        if ((size_t)(last - first) > sizeof(sep_trail)-1 \
                    684:         && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
1.19      nicm      685:                first += sizeof(sep_trail)-2
1.1       millert   686:
                    687: /* Returns the nominal length of the buffer assuming it is termcap format,
                    688:  * i.e., the continuation sequence is treated as a single character ":".
                    689:  *
                    690:  * There are several implementations of termcap which read the text into a
                    691:  * fixed-size buffer.  Generally they strip the newlines from the text, but may
                    692:  * not do it until after the buffer is read.  Also, "tc=" resolution may be
                    693:  * expanded in the same buffer.  This function is useful for measuring the size
                    694:  * of the best fixed-buffer implementation; the worst case may be much worse.
                    695:  */
                    696: #ifdef TEST_TERMCAP_LENGTH
1.10      millert   697: static int
                    698: termcap_length(const char *src)
1.1       millert   699: {
1.10      millert   700:     static const char pattern[] = ":\\\n\t:";
1.1       millert   701:
1.10      millert   702:     int len = 0;
                    703:     const char *const t = src + strlen(src);
1.1       millert   704:
1.10      millert   705:     while (*src != '\0') {
                    706:        IGNORE_SEP_TRAIL(src, t, pattern);
                    707:        src++;
                    708:        len++;
                    709:     }
                    710:     return len;
1.1       millert   711: }
                    712: #else
                    713: #define termcap_length(src) strlen(src)
                    714: #endif
                    715:
1.19      nicm      716: static void
                    717: indent_DYN(DYNBUF * buffer, int level)
                    718: {
                    719:     int n;
                    720:
                    721:     for (n = 0; n < level; n++)
1.21    ! nicm      722:        strncpy_DYN(buffer, "\t", (size_t) 1);
1.19      nicm      723: }
                    724:
1.21    ! nicm      725: /*
        !           726:  * Check if the current line which was begun consists only of a tab and the
        !           727:  * given leading text.
        !           728:  */
1.19      nicm      729: static bool
1.21    ! nicm      730: leading_DYN(DYNBUF * buffer, const char *leading)
        !           731: {
        !           732:     bool result = FALSE;
        !           733:     size_t need = strlen(leading);
        !           734:     if (buffer->used > need) {
        !           735:        need = buffer->used - need;
        !           736:        if (!strcmp(buffer->text + need, leading)) {
        !           737:            result = TRUE;
        !           738:            while (--need != 0) {
        !           739:                if (buffer->text[need] == '\n') {
        !           740:                    break;
        !           741:                }
        !           742:                if (buffer->text[need] != '\t') {
        !           743:                    result = FALSE;
        !           744:                    break;
        !           745:                }
        !           746:            }
        !           747:        }
        !           748:     }
        !           749:     return result;
        !           750: }
        !           751:
        !           752: bool
        !           753: has_params(const char *src, bool formatting)
1.19      nicm      754: {
                    755:     bool result = FALSE;
                    756:     int len = (int) strlen(src);
                    757:     int n;
                    758:     bool ifthen = FALSE;
                    759:     bool params = FALSE;
                    760:
                    761:     for (n = 0; n < len - 1; ++n) {
1.21    ! nicm      762:        if (!strncmp(src + n, "%p", (size_t) 2)) {
1.19      nicm      763:            params = TRUE;
1.21    ! nicm      764:        } else if (!strncmp(src + n, "%;", (size_t) 2)) {
1.19      nicm      765:            ifthen = TRUE;
                    766:            result = params;
                    767:            break;
                    768:        }
                    769:     }
                    770:     if (!ifthen) {
1.21    ! nicm      771:        if (formatting) {
        !           772:            result = ((len > 50) && params);
        !           773:        } else {
        !           774:            result = params;
        !           775:        }
1.19      nicm      776:     }
                    777:     return result;
                    778: }
                    779:
1.10      millert   780: static char *
1.21    ! nicm      781: fmt_complex(TERMTYPE2 *tterm, const char *capability, char *src, int level)
1.1       millert   782: {
1.19      nicm      783:     bool percent = FALSE;
1.21    ! nicm      784:     bool params = has_params(src, TRUE);
1.10      millert   785:
                    786:     while (*src != '\0') {
                    787:        switch (*src) {
1.21    ! nicm      788:        case '^':
        !           789:            percent = FALSE;
        !           790:            strncpy_DYN(&tmpbuf, src++, (size_t) 1);
        !           791:            break;
1.10      millert   792:        case '\\':
1.19      nicm      793:            percent = FALSE;
1.21    ! nicm      794:            strncpy_DYN(&tmpbuf, src++, (size_t) 1);
1.10      millert   795:            break;
                    796:        case '%':
1.19      nicm      797:            percent = TRUE;
1.10      millert   798:            break;
                    799:        case '?':               /* "if" */
                    800:        case 't':               /* "then" */
                    801:        case 'e':               /* "else" */
                    802:            if (percent) {
1.19      nicm      803:                percent = FALSE;
1.15      millert   804:                tmpbuf.text[tmpbuf.used - 1] = '\n';
1.19      nicm      805:                /* treat a "%e" as else-if, on the same level */
                    806:                if (*src == 'e') {
                    807:                    indent_DYN(&tmpbuf, level);
1.21    ! nicm      808:                    strncpy_DYN(&tmpbuf, "%", (size_t) 1);
        !           809:                    strncpy_DYN(&tmpbuf, src, (size_t) 1);
1.19      nicm      810:                    src++;
1.21    ! nicm      811:                    params = has_params(src, TRUE);
1.19      nicm      812:                    if (!params && *src != '\0' && *src != '%') {
1.21    ! nicm      813:                        strncpy_DYN(&tmpbuf, "\n", (size_t) 1);
1.19      nicm      814:                        indent_DYN(&tmpbuf, level + 1);
                    815:                    }
1.15      millert   816:                } else {
1.19      nicm      817:                    indent_DYN(&tmpbuf, level + 1);
1.21    ! nicm      818:                    strncpy_DYN(&tmpbuf, "%", (size_t) 1);
        !           819:                    strncpy_DYN(&tmpbuf, src, (size_t) 1);
1.15      millert   820:                    if (*src++ == '?') {
1.21    ! nicm      821:                        src = fmt_complex(tterm, capability, src, level + 1);
1.19      nicm      822:                        if (*src != '\0' && *src != '%') {
1.21    ! nicm      823:                            strncpy_DYN(&tmpbuf, "\n", (size_t) 1);
1.19      nicm      824:                            indent_DYN(&tmpbuf, level + 1);
                    825:                        }
1.15      millert   826:                    } else if (level == 1) {
1.21    ! nicm      827:                        if (checking)
        !           828:                            _nc_warning("%s: %%%c without %%? in %s",
        !           829:                                        _nc_first_name(tterm->term_names),
        !           830:                                        *src, capability);
1.15      millert   831:                    }
1.10      millert   832:                }
                    833:                continue;
                    834:            }
                    835:            break;
                    836:        case ';':               /* "endif" */
                    837:            if (percent) {
1.19      nicm      838:                percent = FALSE;
1.10      millert   839:                if (level > 1) {
1.15      millert   840:                    tmpbuf.text[tmpbuf.used - 1] = '\n';
1.19      nicm      841:                    indent_DYN(&tmpbuf, level);
1.21    ! nicm      842:                    strncpy_DYN(&tmpbuf, "%", (size_t) 1);
        !           843:                    strncpy_DYN(&tmpbuf, src++, (size_t) 1);
        !           844:                    if (src[0] == '%'
        !           845:                        && src[1] != '\0'
        !           846:                        && (strchr("?e;", src[1])) == 0) {
        !           847:                        tmpbuf.text[tmpbuf.used++] = '\n';
        !           848:                        indent_DYN(&tmpbuf, level);
        !           849:                    }
1.10      millert   850:                    return src;
1.1       millert   851:                }
1.21    ! nicm      852:                if (checking)
        !           853:                    _nc_warning("%s: %%; without %%? in %s",
        !           854:                                _nc_first_name(tterm->term_names),
        !           855:                                capability);
1.10      millert   856:            }
                    857:            break;
                    858:        case 'p':
1.21    ! nicm      859:            if (percent && params && !leading_DYN(&tmpbuf, "%")) {
1.15      millert   860:                tmpbuf.text[tmpbuf.used - 1] = '\n';
1.19      nicm      861:                indent_DYN(&tmpbuf, level + 1);
1.21    ! nicm      862:                strncpy_DYN(&tmpbuf, "%", (size_t) 1);
1.10      millert   863:            }
1.19      nicm      864:            percent = FALSE;
1.10      millert   865:            break;
1.19      nicm      866:        case ' ':
1.21    ! nicm      867:            strncpy_DYN(&tmpbuf, "\\s", (size_t) 2);
1.19      nicm      868:            ++src;
                    869:            continue;
1.10      millert   870:        default:
1.19      nicm      871:            percent = FALSE;
1.10      millert   872:            break;
1.1       millert   873:        }
1.21    ! nicm      874:        strncpy_DYN(&tmpbuf, src++, (size_t) 1);
1.10      millert   875:     }
                    876:     return src;
1.1       millert   877: }
                    878:
1.21    ! nicm      879: /*
        !           880:  * Make "large" numbers a little easier to read by showing them in hexadecimal
        !           881:  * if they are "close" to a power of two.
        !           882:  */
        !           883: static const char *
        !           884: number_format(int value)
        !           885: {
        !           886:     const char *result = "%d";
        !           887:
        !           888:     if ((outform != F_TERMCAP) && (value > 255)) {
        !           889:        unsigned long lv = (unsigned long) value;
        !           890:        int bits = sizeof(unsigned long) * 8;
        !           891:        int nn;
        !           892:
        !           893:        for (nn = 8; nn < bits; ++nn) {
        !           894:            unsigned long mm;
        !           895:
        !           896:            mm = 1UL << nn;
        !           897:            if ((mm - 16) <= lv && (mm + 16) > lv) {
        !           898:                result = "%#x";
        !           899:                break;
        !           900:            }
        !           901:        }
        !           902:     }
        !           903:     return result;
        !           904: }
        !           905:
1.19      nicm      906: #define SAME_CAP(n,cap) (&tterm->Strings[n] == &cap)
                    907: #define EXTRA_CAP 20
                    908:
1.10      millert   909: int
1.21    ! nicm      910: fmt_entry(TERMTYPE2 *tterm,
1.19      nicm      911:          PredFunc pred,
1.21    ! nicm      912:          int content_only,
        !           913:          int suppress_untranslatable,
        !           914:          int infodump,
1.19      nicm      915:          int numbers)
1.10      millert   916: {
1.19      nicm      917:     PredIdx i, j;
                    918:     char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
1.10      millert   919:     NCURSES_CONST char *name;
                    920:     int predval, len;
1.19      nicm      921:     PredIdx num_bools = 0;
                    922:     PredIdx num_values = 0;
                    923:     PredIdx num_strings = 0;
1.10      millert   924:     bool outcount = 0;
1.1       millert   925:
1.21    ! nicm      926: #define WRAP_CONCAT1(s)                wrap_concat1(s); outcount = TRUE
        !           927: #define WRAP_CONCAT            WRAP_CONCAT1(buffer)
1.1       millert   928:
                    929:     len = 12;                  /* terminfo file-header */
                    930:
                    931:     if (pred == 0) {
                    932:        cur_type = tterm;
                    933:        pred = dump_predicate;
                    934:     }
                    935:
1.15      millert   936:     strcpy_DYN(&outbuf, 0);
1.19      nicm      937:     if (content_only) {
1.21    ! nicm      938:        column = indent;        /* workaround to prevent empty lines */
1.19      nicm      939:     } else {
                    940:        strcpy_DYN(&outbuf, tterm->term_names);
1.21    ! nicm      941:
        !           942:        /*
        !           943:         * Colon is legal in terminfo descriptions, but not in termcap.
        !           944:         */
        !           945:        if (!infodump) {
        !           946:            char *p = outbuf.text;
        !           947:            while (*p) {
        !           948:                if (*p == ':') {
        !           949:                    *p = '=';
        !           950:                }
        !           951:                ++p;
        !           952:            }
        !           953:        }
1.19      nicm      954:        strcpy_DYN(&outbuf, separator);
                    955:        column = (int) outbuf.used;
1.21    ! nicm      956:        if (height > 1)
        !           957:            force_wrap();
1.19      nicm      958:     }
1.1       millert   959:
1.10      millert   960:     for_each_boolean(j, tterm) {
1.4       millert   961:        i = BoolIndirect(j);
1.21    ! nicm      962:        name = ExtBoolname(tterm, (int) i, bool_names);
1.19      nicm      963:        assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
1.1       millert   964:
                    965:        if (!version_filter(BOOLEAN, i))
                    966:            continue;
1.10      millert   967:        else if (isObsolete(outform, name))
1.1       millert   968:            continue;
                    969:
                    970:        predval = pred(BOOLEAN, i);
                    971:        if (predval != FAIL) {
1.21    ! nicm      972:            _nc_STRCPY(buffer, name, sizeof(buffer));
1.1       millert   973:            if (predval <= 0)
1.21    ! nicm      974:                _nc_STRCAT(buffer, "@", sizeof(buffer));
1.1       millert   975:            else if (i + 1 > num_bools)
                    976:                num_bools = i + 1;
                    977:            WRAP_CONCAT;
                    978:        }
                    979:     }
                    980:
1.21    ! nicm      981:     if (column != indent && height > 1)
1.1       millert   982:        force_wrap();
                    983:
1.10      millert   984:     for_each_number(j, tterm) {
1.4       millert   985:        i = NumIndirect(j);
1.21    ! nicm      986:        name = ExtNumname(tterm, (int) i, num_names);
1.19      nicm      987:        assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
1.1       millert   988:
                    989:        if (!version_filter(NUMBER, i))
                    990:            continue;
1.10      millert   991:        else if (isObsolete(outform, name))
1.1       millert   992:            continue;
                    993:
                    994:        predval = pred(NUMBER, i);
                    995:        if (predval != FAIL) {
                    996:            if (tterm->Numbers[i] < 0) {
1.21    ! nicm      997:                _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
        !           998:                            "%s@", name);
1.1       millert   999:            } else {
1.21    ! nicm     1000:                size_t nn;
        !          1001:                _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
        !          1002:                            "%s#", name);
        !          1003:                nn = strlen(buffer);
        !          1004:                _nc_SPRINTF(buffer + nn, _nc_SLIMIT(sizeof(buffer) - nn)
        !          1005:                            number_format(tterm->Numbers[i]),
        !          1006:                            tterm->Numbers[i]);
1.1       millert  1007:                if (i + 1 > num_values)
                   1008:                    num_values = i + 1;
                   1009:            }
                   1010:            WRAP_CONCAT;
                   1011:        }
                   1012:     }
                   1013:
1.21    ! nicm     1014:     if (column != indent && height > 1)
1.1       millert  1015:        force_wrap();
                   1016:
1.19      nicm     1017:     len += (int) (num_bools
                   1018:                  + num_values * 2
                   1019:                  + strlen(tterm->term_names) + 1);
1.1       millert  1020:     if (len & 1)
1.10      millert  1021:        len++;
1.1       millert  1022:
1.15      millert  1023: #undef CUR
                   1024: #define CUR tterm->
                   1025:     if (outform == F_TERMCAP) {
1.21    ! nicm     1026:        if (VALID_STRING(termcap_reset)) {
        !          1027:            if (VALID_STRING(init_3string)
1.15      millert  1028:                && !strcmp(init_3string, termcap_reset))
                   1029:                DISCARD(init_3string);
                   1030:
1.21    ! nicm     1031:            if (VALID_STRING(reset_2string)
1.15      millert  1032:                && !strcmp(reset_2string, termcap_reset))
                   1033:                DISCARD(reset_2string);
                   1034:        }
                   1035:     }
                   1036:
1.4       millert  1037:     for_each_string(j, tterm) {
1.21    ! nicm     1038:        char *capability;
1.4       millert  1039:        i = StrIndirect(j);
1.21    ! nicm     1040:        name = ExtStrname(tterm, (int) i, str_names);
1.19      nicm     1041:        assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
                   1042:
                   1043:        capability = tterm->Strings[i];
1.1       millert  1044:
                   1045:        if (!version_filter(STRING, i))
                   1046:            continue;
1.10      millert  1047:        else if (isObsolete(outform, name))
1.1       millert  1048:            continue;
                   1049:
1.19      nicm     1050: #if NCURSES_XNAMES
1.1       millert  1051:        /*
1.19      nicm     1052:         * Extended names can be longer than 2 characters, but termcap programs
                   1053:         * cannot read those (filter them out).
1.1       millert  1054:         */
1.19      nicm     1055:        if (outform == F_TERMCAP && (strlen(name) > 2))
                   1056:            continue;
                   1057: #endif
                   1058:
1.10      millert  1059:        if (outform == F_TERMCAP) {
1.19      nicm     1060:            /*
                   1061:             * Some older versions of vi want rmir/smir to be defined
                   1062:             * for ich/ich1 to work.  If they're not defined, force
                   1063:             * them to be output as defined and empty.
                   1064:             */
                   1065:            if (PRESENT(insert_character) || PRESENT(parm_ich)) {
                   1066:                if (SAME_CAP(i, enter_insert_mode)
1.10      millert  1067:                    && enter_insert_mode == ABSENT_STRING) {
1.21    ! nicm     1068:                    _nc_STRCPY(buffer, "im=", sizeof(buffer));
1.15      millert  1069:                    WRAP_CONCAT;
                   1070:                    continue;
1.1       millert  1071:                }
                   1072:
1.19      nicm     1073:                if (SAME_CAP(i, exit_insert_mode)
1.10      millert  1074:                    && exit_insert_mode == ABSENT_STRING) {
1.21    ! nicm     1075:                    _nc_STRCPY(buffer, "ei=", sizeof(buffer));
1.15      millert  1076:                    WRAP_CONCAT;
                   1077:                    continue;
1.1       millert  1078:                }
                   1079:            }
1.19      nicm     1080:            /*
                   1081:             * termcap applications such as screen will be confused if sgr0
                   1082:             * is translated to a string containing rmacs.  Filter that out.
                   1083:             */
                   1084:            if (PRESENT(exit_attribute_mode)) {
                   1085:                if (SAME_CAP(i, exit_attribute_mode)) {
                   1086:                    char *trimmed_sgr0;
                   1087:                    char *my_sgr = set_attributes;
                   1088:
                   1089:                    set_attributes = save_sgr;
                   1090:
                   1091:                    trimmed_sgr0 = _nc_trim_sgr0(tterm);
1.21    ! nicm     1092:                    if (strcmp(capability, trimmed_sgr0)) {
1.19      nicm     1093:                        capability = trimmed_sgr0;
1.21    ! nicm     1094:                    } else {
        !          1095:                        if (trimmed_sgr0 != exit_attribute_mode)
        !          1096:                            free(trimmed_sgr0);
        !          1097:                    }
1.19      nicm     1098:
                   1099:                    set_attributes = my_sgr;
                   1100:                }
                   1101:            }
1.2       millert  1102:        }
                   1103:
1.1       millert  1104:        predval = pred(STRING, i);
                   1105:        buffer[0] = '\0';
1.15      millert  1106:
1.1       millert  1107:        if (predval != FAIL) {
1.21    ! nicm     1108:            if (VALID_STRING(capability)
1.10      millert  1109:                && i + 1 > num_strings)
1.1       millert  1110:                num_strings = i + 1;
1.15      millert  1111:
1.19      nicm     1112:            if (!VALID_STRING(capability)) {
1.21    ! nicm     1113:                _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
        !          1114:                            "%s@", name);
1.15      millert  1115:                WRAP_CONCAT;
1.21    ! nicm     1116:            } else if (TcOutput()) {
        !          1117:                char *srccap = _nc_tic_expand(capability, TRUE, numbers);
1.19      nicm     1118:                int params = ((i < (int) SIZEOF(parametrized))
                   1119:                              ? parametrized[i]
1.21    ! nicm     1120:                              : ((*srccap == 'k')
        !          1121:                                 ? 0
        !          1122:                                 : has_params(srccap, FALSE)));
1.16      millert  1123:                char *cv = _nc_infotocap(name, srccap, params);
1.1       millert  1124:
1.10      millert  1125:                if (cv == 0) {
1.15      millert  1126:                    if (outform == F_TCONVERR) {
1.21    ! nicm     1127:                        _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
        !          1128:                                    "%s=!!! %s WILL NOT CONVERT !!!",
        !          1129:                                    name, srccap);
        !          1130:                        WRAP_CONCAT;
1.15      millert  1131:                    } else if (suppress_untranslatable) {
1.1       millert  1132:                        continue;
1.15      millert  1133:                    } else {
1.21    ! nicm     1134:                        char *s = srccap, *d = buffer;
        !          1135:                        int need = 3 + (int) strlen(name);
        !          1136:                        while ((*d = *s++) != 0) {
        !          1137:                            if ((d - buffer + 2) >= (int) sizeof(buffer)) {
        !          1138:                                fprintf(stderr,
        !          1139:                                        "%s: value for %s is too long\n",
        !          1140:                                        _nc_progname,
        !          1141:                                        name);
        !          1142:                                *d = '\0';
        !          1143:                                break;
        !          1144:                            }
1.10      millert  1145:                            if (*d == ':') {
                   1146:                                *d++ = '\\';
                   1147:                                *d = ':';
                   1148:                            } else if (*d == '\\') {
1.21    ! nicm     1149:                                if ((*++d = *s++) == '\0')
        !          1150:                                    break;
1.10      millert  1151:                            }
                   1152:                            d++;
1.21    ! nicm     1153:                            *d = '\0';
1.10      millert  1154:                        }
1.21    ! nicm     1155:                        need += (int) (d - buffer);
        !          1156:                        wrap_concat("..", need, w1ST | wERR);
        !          1157:                        need -= 2;
        !          1158:                        wrap_concat(name, need, wOFF | wERR);
        !          1159:                        need -= (int) strlen(name);
        !          1160:                        wrap_concat("=", need, w2ND | wERR);
        !          1161:                        need -= 1;
        !          1162:                        wrap_concat(buffer, need, wEND | wERR);
        !          1163:                        outcount = TRUE;
1.10      millert  1164:                    }
1.15      millert  1165:                } else {
1.21    ! nicm     1166:                    wrap_concat3(name, "=", cv);
1.15      millert  1167:                }
1.19      nicm     1168:                len += (int) strlen(capability) + 1;
1.10      millert  1169:            } else {
1.19      nicm     1170:                char *src = _nc_tic_expand(capability,
                   1171:                                           outform == F_TERMINFO, numbers);
1.15      millert  1172:
                   1173:                strcpy_DYN(&tmpbuf, 0);
                   1174:                strcpy_DYN(&tmpbuf, name);
                   1175:                strcpy_DYN(&tmpbuf, "=");
1.8       millert  1176:                if (pretty
1.10      millert  1177:                    && (outform == F_TERMINFO
1.15      millert  1178:                        || outform == F_VARIABLE)) {
1.21    ! nicm     1179:                    fmt_complex(tterm, name, src, 1);
1.15      millert  1180:                } else {
                   1181:                    strcpy_DYN(&tmpbuf, src);
                   1182:                }
1.19      nicm     1183:                len += (int) strlen(capability) + 1;
1.21    ! nicm     1184:                WRAP_CONCAT1(tmpbuf.text);
1.1       millert  1185:            }
                   1186:        }
1.19      nicm     1187:        /* e.g., trimmed_sgr0 */
1.21    ! nicm     1188:        if (VALID_STRING(capability) &&
        !          1189:            capability != tterm->Strings[i])
1.19      nicm     1190:            free(capability);
1.1       millert  1191:     }
1.19      nicm     1192:     len += (int) (num_strings * 2);
1.1       millert  1193:
                   1194:     /*
                   1195:      * This piece of code should be an effective inverse of the functions
1.19      nicm     1196:      * postprocess_terminfo() and postprocess_terminfo() in parse_entry.c.
1.1       millert  1197:      * Much more work should be done on this to support dumping termcaps.
                   1198:      */
1.10      millert  1199:     if (tversion == V_HPUX) {
1.19      nicm     1200:        if (VALID_STRING(memory_lock)) {
1.21    ! nicm     1201:            _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
        !          1202:                        "meml=%s", memory_lock);
1.1       millert  1203:            WRAP_CONCAT;
                   1204:        }
1.19      nicm     1205:        if (VALID_STRING(memory_unlock)) {
1.21    ! nicm     1206:            _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
        !          1207:                        "memu=%s", memory_unlock);
1.1       millert  1208:            WRAP_CONCAT;
                   1209:        }
1.10      millert  1210:     } else if (tversion == V_AIX) {
                   1211:        if (VALID_STRING(acs_chars)) {
                   1212:            bool box_ok = TRUE;
                   1213:            const char *acstrans = "lqkxjmwuvtn";
                   1214:            const char *cp;
                   1215:            char *tp, *sp, boxchars[11];
1.1       millert  1216:
                   1217:            tp = boxchars;
1.10      millert  1218:            for (cp = acstrans; *cp; cp++) {
1.21    ! nicm     1219:                sp = (strchr) (acs_chars, *cp);
1.1       millert  1220:                if (sp)
                   1221:                    *tp++ = sp[1];
1.10      millert  1222:                else {
1.1       millert  1223:                    box_ok = FALSE;
                   1224:                    break;
                   1225:                }
                   1226:            }
                   1227:            tp[0] = '\0';
                   1228:
1.10      millert  1229:            if (box_ok) {
1.21    ! nicm     1230:                char *tmp = _nc_tic_expand(boxchars,
        !          1231:                                           (outform == F_TERMINFO),
        !          1232:                                           numbers);
        !          1233:                _nc_STRCPY(buffer, "box1=", sizeof(buffer));
        !          1234:                while (*tmp != '\0') {
        !          1235:                    size_t have = strlen(buffer);
        !          1236:                    size_t next = strlen(tmp);
        !          1237:                    size_t want = have + next + 1;
        !          1238:                    size_t last = next;
        !          1239:                    char save = '\0';
        !          1240:
        !          1241:                    /*
        !          1242:                     * If the expanded string is too long for the buffer,
        !          1243:                     * chop it off and save the location where we chopped it.
        !          1244:                     */
        !          1245:                    if (want >= sizeof(buffer)) {
        !          1246:                        save = tmp[last];
        !          1247:                        tmp[last] = '\0';
        !          1248:                    }
        !          1249:                    _nc_STRCAT(buffer, tmp, sizeof(buffer));
        !          1250:
        !          1251:                    /*
        !          1252:                     * If we chopped the buffer, replace the missing piece and
        !          1253:                     * shift everything to append the remainder.
        !          1254:                     */
        !          1255:                    if (save != '\0') {
        !          1256:                        next = 0;
        !          1257:                        tmp[last] = save;
        !          1258:                        while ((tmp[next] = tmp[last + next]) != '\0') {
        !          1259:                            ++next;
        !          1260:                        }
        !          1261:                    } else {
        !          1262:                        break;
        !          1263:                    }
        !          1264:                }
1.1       millert  1265:                WRAP_CONCAT;
                   1266:            }
                   1267:        }
                   1268:     }
                   1269:
                   1270:     /*
                   1271:      * kludge: trim off trailer to avoid an extra blank line
                   1272:      * in infocmp -u output when there are no string differences
                   1273:      */
1.10      millert  1274:     if (outcount) {
1.15      millert  1275:        bool trimmed = FALSE;
1.21    ! nicm     1276:        j = (PredIdx) outbuf.used;
        !          1277:        if (wrapped && did_wrap) {
        !          1278:            /* EMPTY */ ;
        !          1279:        } else if (j >= 2
        !          1280:                   && outbuf.text[j - 1] == '\t'
        !          1281:                   && outbuf.text[j - 2] == '\n') {
1.15      millert  1282:            outbuf.used -= 2;
                   1283:            trimmed = TRUE;
1.1       millert  1284:        } else if (j >= 4
1.19      nicm     1285:                   && outbuf.text[j - 1] == ':'
                   1286:                   && outbuf.text[j - 2] == '\t'
                   1287:                   && outbuf.text[j - 3] == '\n'
                   1288:                   && outbuf.text[j - 4] == '\\') {
1.15      millert  1289:            outbuf.used -= 4;
                   1290:            trimmed = TRUE;
                   1291:        }
                   1292:        if (trimmed) {
                   1293:            outbuf.text[outbuf.used] = '\0';
                   1294:            column = oldcol;
1.19      nicm     1295:            strcpy_DYN(&outbuf, " ");
1.1       millert  1296:        }
                   1297:     }
                   1298: #if 0
                   1299:     fprintf(stderr, "num_bools = %d\n", num_bools);
                   1300:     fprintf(stderr, "num_values = %d\n", num_values);
                   1301:     fprintf(stderr, "num_strings = %d\n", num_strings);
                   1302:     fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
1.19      nicm     1303:            tterm->term_names, len, outbuf.used, outbuf.text);
1.1       millert  1304: #endif
                   1305:     /*
                   1306:      * Here's where we use infodump to trigger a more stringent length check
                   1307:      * for termcap-translation purposes.
                   1308:      * Return the length of the raw entry, without tc= expansions,
                   1309:      * It gives an idea of which entries are deadly to even *scan past*,
                   1310:      * as opposed to *use*.
                   1311:      */
1.19      nicm     1312:     return (infodump ? len : (int) termcap_length(outbuf.text));
                   1313: }
                   1314:
                   1315: static bool
1.21    ! nicm     1316: kill_string(TERMTYPE2 *tterm, const char *const cap)
1.19      nicm     1317: {
                   1318:     unsigned n;
                   1319:     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
                   1320:        if (cap == tterm->Strings[n]) {
                   1321:            tterm->Strings[n] = ABSENT_STRING;
                   1322:            return TRUE;
                   1323:        }
                   1324:     }
                   1325:     return FALSE;
1.1       millert  1326: }
                   1327:
1.19      nicm     1328: static char *
1.21    ! nicm     1329: find_string(TERMTYPE2 *tterm, char *name)
1.19      nicm     1330: {
                   1331:     PredIdx n;
                   1332:     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
                   1333:        if (version_filter(STRING, n)
                   1334:            && !strcmp(name, strnames[n])) {
                   1335:            char *cap = tterm->Strings[n];
                   1336:            if (VALID_STRING(cap)) {
                   1337:                return cap;
                   1338:            }
                   1339:            break;
                   1340:        }
                   1341:     }
                   1342:     return ABSENT_STRING;
                   1343: }
                   1344:
                   1345: /*
                   1346:  * This is used to remove function-key labels from a termcap entry to
                   1347:  * make it smaller.
                   1348:  */
                   1349: static int
1.21    ! nicm     1350: kill_labels(TERMTYPE2 *tterm, int target)
1.19      nicm     1351: {
                   1352:     int n;
                   1353:     int result = 0;
1.21    ! nicm     1354:     char name[20];
1.19      nicm     1355:
                   1356:     for (n = 0; n <= 10; ++n) {
1.21    ! nicm     1357:        char *cap;
        !          1358:
        !          1359:        _nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "lf%d", n);
        !          1360:        cap = find_string(tterm, name);
        !          1361:        if (VALID_STRING(cap)
1.19      nicm     1362:            && kill_string(tterm, cap)) {
                   1363:            target -= (int) (strlen(cap) + 5);
                   1364:            ++result;
                   1365:            if (target < 0)
                   1366:                break;
                   1367:        }
                   1368:     }
                   1369:     return result;
                   1370: }
                   1371:
                   1372: /*
                   1373:  * This is used to remove function-key definitions from a termcap entry to
                   1374:  * make it smaller.
                   1375:  */
                   1376: static int
1.21    ! nicm     1377: kill_fkeys(TERMTYPE2 *tterm, int target)
1.19      nicm     1378: {
                   1379:     int n;
                   1380:     int result = 0;
1.21    ! nicm     1381:     char name[20];
1.19      nicm     1382:
                   1383:     for (n = 60; n >= 0; --n) {
1.21    ! nicm     1384:        char *cap;
        !          1385:
        !          1386:        _nc_SPRINTF(name, _nc_SLIMIT(sizeof(name)) "kf%d", n);
        !          1387:        cap = find_string(tterm, name);
        !          1388:        if (VALID_STRING(cap)
1.19      nicm     1389:            && kill_string(tterm, cap)) {
                   1390:            target -= (int) (strlen(cap) + 5);
                   1391:            ++result;
                   1392:            if (target < 0)
                   1393:                break;
                   1394:        }
                   1395:     }
                   1396:     return result;
                   1397: }
                   1398:
                   1399: /*
                   1400:  * Check if the given acsc string is a 1-1 mapping, i.e., just-like-vt100.
                   1401:  * Also, since this is for termcap, we only care about the line-drawing map.
                   1402:  */
                   1403: #define isLine(c) (strchr("lmkjtuvwqxn", c) != 0)
                   1404:
                   1405: static bool
                   1406: one_one_mapping(const char *mapping)
                   1407: {
                   1408:     bool result = TRUE;
                   1409:
1.21    ! nicm     1410:     if (VALID_STRING(mapping)) {
1.19      nicm     1411:        int n = 0;
1.21    ! nicm     1412:        while (mapping[n] != '\0' && mapping[n + 1] != '\0') {
1.19      nicm     1413:            if (isLine(mapping[n]) &&
                   1414:                mapping[n] != mapping[n + 1]) {
                   1415:                result = FALSE;
                   1416:                break;
                   1417:            }
                   1418:            n += 2;
                   1419:        }
                   1420:     }
                   1421:     return result;
                   1422: }
                   1423:
                   1424: #define FMT_ENTRY() \
                   1425:                fmt_entry(tterm, pred, \
                   1426:                        0, \
                   1427:                        suppress_untranslatable, \
                   1428:                        infodump, numbers)
                   1429:
                   1430: #define SHOW_WHY PRINTF
                   1431:
                   1432: static bool
1.21    ! nicm     1433: purged_acs(TERMTYPE2 *tterm)
1.19      nicm     1434: {
                   1435:     bool result = FALSE;
                   1436:
                   1437:     if (VALID_STRING(acs_chars)) {
                   1438:        if (!one_one_mapping(acs_chars)) {
                   1439:            enter_alt_charset_mode = ABSENT_STRING;
                   1440:            exit_alt_charset_mode = ABSENT_STRING;
                   1441:            SHOW_WHY("# (rmacs/smacs removed for consistency)\n");
                   1442:        }
                   1443:        result = TRUE;
                   1444:     }
                   1445:     return result;
                   1446: }
                   1447:
1.21    ! nicm     1448: static void
        !          1449: encode_b64(char *target, char *source, unsigned state, int *saved)
        !          1450: {
        !          1451:     /* RFC-4648 */
        !          1452:     static const char data[] =
        !          1453:     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        !          1454:     "abcdefghijklmnopqrstuvwxyz"
        !          1455:     "0123456789" "-_";
        !          1456:     int ch = UChar(source[state]);
        !          1457:
        !          1458:     switch (state % 3) {
        !          1459:     case 0:
        !          1460:        *target++ = data[(ch >> 2) & 077];
        !          1461:        *saved = (ch << 4);
        !          1462:        break;
        !          1463:     case 1:
        !          1464:        *target++ = data[((ch >> 4) | *saved) & 077];
        !          1465:        *saved = (ch << 2);
        !          1466:        break;
        !          1467:     case 2:
        !          1468:        *target++ = data[((ch >> 6) | *saved) & 077];
        !          1469:        *target++ = data[ch & 077];
        !          1470:        *saved = 0;
        !          1471:        break;
        !          1472:     }
        !          1473:     *target = '\0';
        !          1474: }
        !          1475:
1.19      nicm     1476: /*
                   1477:  * Dump a single entry.
                   1478:  */
                   1479: void
1.21    ! nicm     1480: dump_entry(TERMTYPE2 *tterm,
        !          1481:           int suppress_untranslatable,
        !          1482:           int limited,
1.19      nicm     1483:           int numbers,
                   1484:           PredFunc pred)
1.1       millert  1485: {
1.21    ! nicm     1486:     TERMTYPE2 save_tterm;
        !          1487:     int critlen;
1.10      millert  1488:     const char *legend;
                   1489:     bool infodump;
1.1       millert  1490:
1.21    ! nicm     1491:     if (quickdump) {
        !          1492:        char bigbuf[65536];
        !          1493:        unsigned offset = 0;
        !          1494:
        !          1495:        separator = "";
        !          1496:        trailer = "\n";
        !          1497:        indent = 0;
        !          1498:
        !          1499:        if (_nc_write_object(tterm, bigbuf, &offset, sizeof(bigbuf)) == OK) {
        !          1500:            char numbuf[80];
        !          1501:            unsigned n;
        !          1502:
        !          1503:            if (quickdump & 1) {
        !          1504:                if (outbuf.used)
        !          1505:                    wrap_concat1("\n");
        !          1506:                wrap_concat1("hex:");
        !          1507:                for (n = 0; n < offset; ++n) {
        !          1508:                    _nc_SPRINTF(numbuf, _nc_SLIMIT(sizeof(numbuf))
        !          1509:                                "%02X", UChar(bigbuf[n]));
        !          1510:                    wrap_concat1(numbuf);
        !          1511:                }
        !          1512:            }
        !          1513:            if (quickdump & 2) {
        !          1514:                static char padding[] =
        !          1515:                {0, 0};
        !          1516:                int value = 0;
        !          1517:
        !          1518:                if (outbuf.used)
        !          1519:                    wrap_concat1("\n");
        !          1520:                wrap_concat1("b64:");
        !          1521:                for (n = 0; n < offset; ++n) {
        !          1522:                    encode_b64(numbuf, bigbuf, n, &value);
        !          1523:                    wrap_concat1(numbuf);
        !          1524:                }
        !          1525:                switch (n % 3) {
        !          1526:                case 0:
        !          1527:                    break;
        !          1528:                case 1:
        !          1529:                    encode_b64(numbuf, padding, 1, &value);
        !          1530:                    wrap_concat1(numbuf);
        !          1531:                    wrap_concat1("==");
        !          1532:                    break;
        !          1533:                case 2:
        !          1534:                    encode_b64(numbuf, padding, 1, &value);
        !          1535:                    wrap_concat1(numbuf);
        !          1536:                    wrap_concat1("=");
        !          1537:                    break;
        !          1538:                }
        !          1539:            }
        !          1540:        }
        !          1541:        return;
        !          1542:     }
        !          1543:
        !          1544:     if (TcOutput()) {
1.1       millert  1545:        critlen = MAX_TERMCAP_LENGTH;
                   1546:        legend = "older termcap";
                   1547:        infodump = FALSE;
                   1548:        set_obsolete_termcaps(tterm);
1.10      millert  1549:     } else {
1.1       millert  1550:        critlen = MAX_TERMINFO_LENGTH;
                   1551:        legend = "terminfo";
                   1552:        infodump = TRUE;
                   1553:     }
                   1554:
1.19      nicm     1555:     save_sgr = set_attributes;
                   1556:
1.21    ! nicm     1557:     if ((FMT_ENTRY() > critlen)
        !          1558:        && TcOutput()
1.10      millert  1559:        && limited) {
1.19      nicm     1560:
                   1561:        save_tterm = *tterm;
                   1562:        if (!suppress_untranslatable) {
                   1563:            SHOW_WHY("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
                   1564:                     critlen);
                   1565:            suppress_untranslatable = TRUE;
                   1566:        }
1.21    ! nicm     1567:        if (FMT_ENTRY() > critlen) {
1.1       millert  1568:            /*
1.21    ! nicm     1569:             * We pick on sgr because it is a nice long string capability that
1.12      millert  1570:             * is really just an optimization hack.  Another good candidate is
                   1571:             * acsc since it is both long and unused by BSD termcap.
1.1       millert  1572:             */
1.19      nicm     1573:            bool changed = FALSE;
                   1574:
                   1575: #if NCURSES_XNAMES
                   1576:            /*
                   1577:             * Extended names are most likely function-key definitions.  Drop
                   1578:             * those first.
                   1579:             */
                   1580:            unsigned n;
                   1581:            for (n = STRCOUNT; n < NUM_STRINGS(tterm); n++) {
1.21    ! nicm     1582:                const char *name = ExtStrname(tterm, (int) n, strnames);
1.19      nicm     1583:
                   1584:                if (VALID_STRING(tterm->Strings[n])) {
                   1585:                    set_attributes = ABSENT_STRING;
                   1586:                    /* we remove long names anyway - only report the short */
                   1587:                    if (strlen(name) <= 2) {
                   1588:                        SHOW_WHY("# (%s removed to fit entry within %d bytes)\n",
                   1589:                                 name,
                   1590:                                 critlen);
                   1591:                    }
                   1592:                    changed = TRUE;
1.21    ! nicm     1593:                    if (FMT_ENTRY() <= critlen)
1.19      nicm     1594:                        break;
                   1595:                }
1.12      millert  1596:            }
1.19      nicm     1597: #endif
                   1598:            if (VALID_STRING(set_attributes)) {
                   1599:                set_attributes = ABSENT_STRING;
                   1600:                SHOW_WHY("# (sgr removed to fit entry within %d bytes)\n",
                   1601:                         critlen);
                   1602:                changed = TRUE;
                   1603:            }
1.21    ! nicm     1604:            if (!changed || (FMT_ENTRY() > critlen)) {
1.19      nicm     1605:                if (purged_acs(tterm)) {
                   1606:                    acs_chars = ABSENT_STRING;
                   1607:                    SHOW_WHY("# (acsc removed to fit entry within %d bytes)\n",
                   1608:                             critlen);
                   1609:                    changed = TRUE;
                   1610:                }
                   1611:            }
1.21    ! nicm     1612:            if (!changed || (FMT_ENTRY() > critlen)) {
1.1       millert  1613:                int oldversion = tversion;
1.21    ! nicm     1614:                int len;
1.1       millert  1615:
                   1616:                tversion = V_BSD;
1.19      nicm     1617:                SHOW_WHY("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
                   1618:                         critlen);
1.1       millert  1619:
1.19      nicm     1620:                len = FMT_ENTRY();
                   1621:                if (len > critlen
                   1622:                    && kill_labels(tterm, len - critlen)) {
                   1623:                    SHOW_WHY("# (some labels capabilities suppressed to fit entry within %d bytes)\n",
                   1624:                             critlen);
                   1625:                    len = FMT_ENTRY();
                   1626:                }
                   1627:                if (len > critlen
                   1628:                    && kill_fkeys(tterm, len - critlen)) {
                   1629:                    SHOW_WHY("# (some function-key capabilities suppressed to fit entry within %d bytes)\n",
                   1630:                             critlen);
                   1631:                    len = FMT_ENTRY();
                   1632:                }
                   1633:                if (len > critlen) {
1.1       millert  1634:                    (void) fprintf(stderr,
1.21    ! nicm     1635:                                   "%s: %s entry is %d bytes long\n",
        !          1636:                                   _nc_progname,
1.19      nicm     1637:                                   _nc_first_name(tterm->term_names),
                   1638:                                   len);
                   1639:                    SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
                   1640:                             len, legend);
1.1       millert  1641:                }
                   1642:                tversion = oldversion;
                   1643:            }
1.19      nicm     1644:            set_attributes = save_sgr;
                   1645:            *tterm = save_tterm;
                   1646:        }
                   1647:     } else if (!version_filter(STRING, STR_IDX(acs_chars))) {
                   1648:        save_tterm = *tterm;
                   1649:        if (purged_acs(tterm)) {
1.21    ! nicm     1650:            (void) FMT_ENTRY();
1.1       millert  1651:        }
1.19      nicm     1652:        *tterm = save_tterm;
1.1       millert  1653:     }
                   1654: }
                   1655:
1.19      nicm     1656: void
1.21    ! nicm     1657: dump_uses(const char *value, bool infodump)
1.1       millert  1658: /* dump "use=" clauses in the appropriate format */
                   1659: {
1.21    ! nicm     1660:     char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
        !          1661:     int limit = (VALID_STRING(value) ? (int) strlen(value) : 0);
        !          1662:     const char *cap = infodump ? "use" : "tc";
1.1       millert  1663:
1.21    ! nicm     1664:     if (TcOutput())
1.19      nicm     1665:        trim_trailing();
1.21    ! nicm     1666:     if (limit == 0) {
        !          1667:        _nc_warning("empty \"%s\" field", cap);
        !          1668:        value = "";
        !          1669:     } else if (limit > MAX_ALIAS) {
        !          1670:        _nc_warning("\"%s\" field too long (%d), limit to %d",
        !          1671:                    cap, limit, MAX_ALIAS);
        !          1672:        limit = MAX_ALIAS;
        !          1673:     }
        !          1674:     _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
        !          1675:                "%s=%.*s", cap, limit, value);
        !          1676:     wrap_concat1(buffer);
1.19      nicm     1677: }
                   1678:
                   1679: int
                   1680: show_entry(void)
                   1681: {
1.21    ! nicm     1682:     /*
        !          1683:      * Trim any remaining whitespace.
        !          1684:      */
        !          1685:     if (outbuf.used != 0) {
        !          1686:        bool infodump = !TcOutput();
        !          1687:        char delim = (char) (infodump ? ',' : ':');
        !          1688:        int j;
        !          1689:
        !          1690:        for (j = (int) outbuf.used - 1; j > 0; --j) {
        !          1691:            char ch = outbuf.text[j];
        !          1692:            if (ch == '\n') {
        !          1693:                ;
        !          1694:            } else if (isspace(UChar(ch))) {
        !          1695:                outbuf.used = (size_t) j;
        !          1696:            } else if (!infodump && ch == '\\') {
        !          1697:                outbuf.used = (size_t) j;
        !          1698:            } else if (ch == delim && (outbuf.text[j - 1] != '\\')) {
        !          1699:                outbuf.used = (size_t) (j + 1);
        !          1700:            } else {
        !          1701:                break;
        !          1702:            }
        !          1703:        }
        !          1704:        outbuf.text[outbuf.used] = '\0';
        !          1705:     }
        !          1706:     if (outbuf.text != 0) {
        !          1707:        (void) fputs(outbuf.text, stdout);
        !          1708:        putchar('\n');
        !          1709:     }
1.19      nicm     1710:     return (int) outbuf.used;
1.1       millert  1711: }
                   1712:
1.10      millert  1713: void
1.21    ! nicm     1714: compare_entry(PredHook hook,
        !          1715:              TERMTYPE2 *tp GCC_UNUSED,
1.19      nicm     1716:              bool quiet)
1.1       millert  1717: /* compare two entries */
                   1718: {
1.19      nicm     1719:     PredIdx i, j;
1.10      millert  1720:     NCURSES_CONST char *name;
1.1       millert  1721:
1.15      millert  1722:     if (!quiet)
                   1723:        fputs("    comparing booleans.\n", stdout);
1.10      millert  1724:     for_each_boolean(j, tp) {
1.4       millert  1725:        i = BoolIndirect(j);
1.21    ! nicm     1726:        name = ExtBoolname(tp, (int) i, bool_names);
1.1       millert  1727:
1.10      millert  1728:        if (isObsolete(outform, name))
1.1       millert  1729:            continue;
                   1730:
1.14      millert  1731:        (*hook) (CMP_BOOLEAN, i, name);
1.1       millert  1732:     }
                   1733:
1.15      millert  1734:     if (!quiet)
                   1735:        fputs("    comparing numbers.\n", stdout);
1.10      millert  1736:     for_each_number(j, tp) {
1.4       millert  1737:        i = NumIndirect(j);
1.21    ! nicm     1738:        name = ExtNumname(tp, (int) i, num_names);
1.1       millert  1739:
1.10      millert  1740:        if (isObsolete(outform, name))
1.1       millert  1741:            continue;
                   1742:
1.14      millert  1743:        (*hook) (CMP_NUMBER, i, name);
1.1       millert  1744:     }
                   1745:
1.15      millert  1746:     if (!quiet)
                   1747:        fputs("    comparing strings.\n", stdout);
1.10      millert  1748:     for_each_string(j, tp) {
1.4       millert  1749:        i = StrIndirect(j);
1.21    ! nicm     1750:        name = ExtStrname(tp, (int) i, str_names);
1.1       millert  1751:
1.10      millert  1752:        if (isObsolete(outform, name))
1.1       millert  1753:            continue;
                   1754:
1.14      millert  1755:        (*hook) (CMP_STRING, i, name);
1.1       millert  1756:     }
1.14      millert  1757:
                   1758:     /* (void) fputs("    comparing use entries.\n", stdout); */
                   1759:     (*hook) (CMP_USE, 0, "use");
                   1760:
1.1       millert  1761: }
                   1762:
                   1763: #define NOTSET(s)      ((s) == 0)
                   1764:
                   1765: /*
                   1766:  * This bit of legerdemain turns all the terminfo variable names into
                   1767:  * references to locations in the arrays Booleans, Numbers, and Strings ---
                   1768:  * precisely what's needed.
                   1769:  */
                   1770: #undef CUR
                   1771: #define CUR tp->
                   1772:
1.10      millert  1773: static void
1.21    ! nicm     1774: set_obsolete_termcaps(TERMTYPE2 *tp)
1.1       millert  1775: {
                   1776: #include "capdefaults.c"
                   1777: }
                   1778:
                   1779: /*
                   1780:  * Convert an alternate-character-set string to canonical form: sorted and
                   1781:  * unique.
                   1782:  */
1.14      millert  1783: void
1.21    ! nicm     1784: repair_acsc(TERMTYPE2 *tp)
1.1       millert  1785: {
1.10      millert  1786:     if (VALID_STRING(acs_chars)) {
1.21    ! nicm     1787:        size_t n;
1.10      millert  1788:        char mapped[256];
                   1789:        unsigned source;
                   1790:        unsigned target;
                   1791:        bool fix_needed = FALSE;
                   1792:
                   1793:        for (n = 0, source = 0; acs_chars[n] != 0; n++) {
1.19      nicm     1794:            target = UChar(acs_chars[n]);
1.10      millert  1795:            if (source >= target) {
                   1796:                fix_needed = TRUE;
                   1797:                break;
                   1798:            }
                   1799:            source = target;
                   1800:            if (acs_chars[n + 1])
                   1801:                n++;
                   1802:        }
1.21    ! nicm     1803:
1.10      millert  1804:        if (fix_needed) {
1.21    ! nicm     1805:            size_t m;
        !          1806:            char extra = 0;
        !          1807:
1.10      millert  1808:            memset(mapped, 0, sizeof(mapped));
                   1809:            for (n = 0; acs_chars[n] != 0; n++) {
1.19      nicm     1810:                source = UChar(acs_chars[n]);
1.10      millert  1811:                if ((target = (unsigned char) acs_chars[n + 1]) != 0) {
1.19      nicm     1812:                    mapped[source] = (char) target;
1.10      millert  1813:                    n++;
                   1814:                } else {
1.19      nicm     1815:                    extra = (char) source;
1.1       millert  1816:                }
                   1817:            }
1.10      millert  1818:            for (n = m = 0; n < sizeof(mapped); n++) {
                   1819:                if (mapped[n]) {
1.19      nicm     1820:                    acs_chars[m++] = (char) n;
1.10      millert  1821:                    acs_chars[m++] = mapped[n];
1.1       millert  1822:                }
                   1823:            }
1.10      millert  1824:            if (extra)
                   1825:                acs_chars[m++] = extra;         /* garbage in, garbage out */
                   1826:            acs_chars[m] = 0;
1.1       millert  1827:        }
1.10      millert  1828:     }
1.1       millert  1829: }