[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.19

1.18      millert     1: /*     $OpenBSD: dump_entry.c,v 1.17 2003/04/06 18:38:42 deraadt Exp $ */
1.2       millert     2:
1.1       millert     3: /****************************************************************************
1.19    ! nicm        4:  * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
1.1       millert     5:  *                                                                          *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a  *
                      7:  * copy of this software and associated documentation files (the            *
                      8:  * "Software"), to deal in the Software without restriction, including      *
                      9:  * without limitation the rights to use, copy, modify, merge, publish,      *
                     10:  * distribute, distribute with modifications, sublicense, and/or sell       *
                     11:  * copies of the Software, and to permit persons to whom the Software is    *
                     12:  * furnished to do so, subject to the following conditions:                 *
                     13:  *                                                                          *
                     14:  * The above copyright notice and this permission notice shall be included  *
                     15:  * in all copies or substantial portions of the Software.                   *
                     16:  *                                                                          *
                     17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
                     18:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
                     19:  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
                     20:  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
                     21:  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
                     22:  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
                     23:  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
                     24:  *                                                                          *
                     25:  * Except as contained in this notice, the name(s) of the above copyright   *
                     26:  * holders shall not be used in advertising or otherwise to promote the     *
                     27:  * sale, use or other dealings in this Software without prior written       *
                     28:  * authorization.                                                           *
                     29:  ****************************************************************************/
                     30:
                     31: /****************************************************************************
                     32:  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
                     33:  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
1.19    ! nicm       34:  *     and: Thomas E. Dickey                        1996 on                 *
1.1       millert    35:  ****************************************************************************/
                     36:
                     37: #define __INTERNAL_CAPS_VISIBLE
                     38: #include <progs.priv.h>
                     39:
                     40: #include "dump_entry.h"
1.19    ! nicm       41: #include "termsort.c"          /* this C file is generated */
1.1       millert    42: #include <parametrized.h>      /* so is this */
                     43:
1.19    ! nicm       44: MODULE_ID("$Id: dump_entry.c,v 1.88 2008/08/04 12:36:12 tom Exp $")
1.11      millert    45:
1.1       millert    46: #define INDENT                 8
1.2       millert    47: #define DISCARD(string) string = ABSENT_STRING
1.11      millert    48: #define PRINTF (void) printf
1.2       millert    49:
1.19    ! nicm       50: #define OkIndex(index,array) ((int)(index) >= 0 && (int)(index) < (int) SIZEOF(array))
        !            51:
1.15      millert    52: typedef struct {
                     53:     char *text;
                     54:     size_t used;
                     55:     size_t size;
                     56: } DYNBUF;
                     57:
1.11      millert    58: static int tversion;           /* terminfo version */
                     59: static int outform;            /* output format to use */
                     60: static int sortmode;           /* sort mode to use */
                     61: static int width = 60;         /* max line width for listings */
                     62: static int column;             /* current column, limited by 'width' */
                     63: static int oldcol;             /* last value of column before wrap */
                     64: static bool pretty;            /* true if we format if-then-else strings */
                     65:
1.19    ! nicm       66: static char *save_sgr;
        !            67:
1.15      millert    68: static DYNBUF outbuf;
                     69: static DYNBUF tmpbuf;
1.1       millert    70:
                     71: /* indirection pointers for implementing sort and display modes */
1.19    ! nicm       72: static const PredIdx *bool_indirect, *num_indirect, *str_indirect;
1.11      millert    73: static NCURSES_CONST char *const *bool_names;
                     74: static NCURSES_CONST char *const *num_names;
                     75: static NCURSES_CONST char *const *str_names;
1.1       millert    76:
1.11      millert    77: static const char *separator, *trailer;
1.1       millert    78:
                     79: /* cover various ports and variants of terminfo */
                     80: #define V_ALLCAPS      0       /* all capabilities (SVr4, XSI, ncurses) */
                     81: #define V_SVR1         1       /* SVR1, Ultrix */
                     82: #define V_HPUX         2       /* HP/UX */
                     83: #define V_AIX          3       /* AIX */
                     84: #define V_BSD          4       /* BSD */
                     85:
1.9       millert    86: #if NCURSES_XNAMES
                     87: #define OBSOLETE(n) (!_nc_user_definable && (n[0] == 'O' && n[1] == 'T'))
                     88: #else
1.1       millert    89: #define OBSOLETE(n) (n[0] == 'O' && n[1] == 'T')
1.9       millert    90: #endif
                     91:
                     92: #define isObsolete(f,n) ((f == F_TERMINFO || f == F_VARIABLE) && OBSOLETE(n))
1.1       millert    93:
1.4       millert    94: #if NCURSES_XNAMES
                     95: #define BoolIndirect(j) ((j >= BOOLCOUNT) ? (j) : ((sortmode == S_NOSORT) ? j : bool_indirect[j]))
                     96: #define NumIndirect(j)  ((j >= NUMCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : num_indirect[j]))
                     97: #define StrIndirect(j)  ((j >= STRCOUNT)  ? (j) : ((sortmode == S_NOSORT) ? j : str_indirect[j]))
                     98: #else
                     99: #define BoolIndirect(j) ((sortmode == S_NOSORT) ? (j) : bool_indirect[j])
                    100: #define NumIndirect(j)  ((sortmode == S_NOSORT) ? (j) : num_indirect[j])
                    101: #define StrIndirect(j)  ((sortmode == S_NOSORT) ? (j) : str_indirect[j])
                    102: #endif
                    103:
1.15      millert   104: static void
                    105: strncpy_DYN(DYNBUF * dst, const char *src, size_t need)
                    106: {
                    107:     size_t want = need + dst->used + 1;
                    108:     if (want > dst->size) {
                    109:        dst->size += (want + 1024);     /* be generous */
                    110:        dst->text = typeRealloc(char, dst->size, dst->text);
                    111:     }
                    112:     (void) strncpy(dst->text + dst->used, src, need);
                    113:     dst->used += need;
                    114:     dst->text[dst->used] = 0;
                    115: }
                    116:
                    117: static void
                    118: strcpy_DYN(DYNBUF * dst, const char *src)
                    119: {
                    120:     if (src == 0) {
                    121:        dst->used = 0;
                    122:        strcpy_DYN(dst, "");
                    123:     } else {
                    124:        strncpy_DYN(dst, src, strlen(src));
                    125:     }
                    126: }
                    127:
1.1       millert   128: #if NO_LEAKS
1.15      millert   129: static void
                    130: free_DYN(DYNBUF * p)
                    131: {
                    132:     if (p->text != 0)
                    133:        free(p->text);
                    134:     p->text = 0;
                    135:     p->size = 0;
                    136:     p->used = 0;
                    137: }
                    138:
1.11      millert   139: void
                    140: _nc_leaks_dump_entry(void)
1.1       millert   141: {
1.15      millert   142:     free_DYN(&outbuf);
                    143:     free_DYN(&tmpbuf);
1.1       millert   144: }
                    145: #endif
                    146:
1.19    ! nicm      147: #define NameTrans(check,result) \
        !           148:            if (OkIndex(np->nte_index, check) \
        !           149:                && check[np->nte_index]) \
        !           150:                return (result[np->nte_index])
        !           151:
1.10      millert   152: NCURSES_CONST char *
                    153: nametrans(const char *name)
1.1       millert   154: /* translate a capability name from termcap to terminfo */
                    155: {
1.10      millert   156:     const struct name_table_entry *np;
1.1       millert   157:
1.3       millert   158:     if ((np = _nc_find_entry(name, _nc_get_hash_table(0))) != 0)
1.10      millert   159:        switch (np->nte_type) {
1.1       millert   160:        case BOOLEAN:
1.19    ! nicm      161:            NameTrans(bool_from_termcap, boolcodes);
1.1       millert   162:            break;
                    163:
                    164:        case NUMBER:
1.19    ! nicm      165:            NameTrans(num_from_termcap, numcodes);
1.1       millert   166:            break;
                    167:
                    168:        case STRING:
1.19    ! nicm      169:            NameTrans(str_from_termcap, strcodes);
1.1       millert   170:            break;
                    171:        }
                    172:
1.10      millert   173:     return (0);
1.1       millert   174: }
                    175:
1.10      millert   176: void
                    177: dump_init(const char *version, int mode, int sort, int twidth, int traceval,
1.19    ! nicm      178:          bool formatted)
1.1       millert   179: /* set up for entry display */
                    180: {
                    181:     width = twidth;
                    182:     pretty = formatted;
                    183:
                    184:     /* versions */
                    185:     if (version == 0)
                    186:        tversion = V_ALLCAPS;
                    187:     else if (!strcmp(version, "SVr1") || !strcmp(version, "SVR1")
1.19    ! nicm      188:             || !strcmp(version, "Ultrix"))
1.1       millert   189:        tversion = V_SVR1;
                    190:     else if (!strcmp(version, "HP"))
                    191:        tversion = V_HPUX;
                    192:     else if (!strcmp(version, "AIX"))
                    193:        tversion = V_AIX;
                    194:     else if (!strcmp(version, "BSD"))
                    195:        tversion = V_BSD;
                    196:     else
                    197:        tversion = V_ALLCAPS;
                    198:
                    199:     /* implement display modes */
1.10      millert   200:     switch (outform = mode) {
1.1       millert   201:     case F_LITERAL:
                    202:     case F_TERMINFO:
                    203:        bool_names = boolnames;
                    204:        num_names = numnames;
                    205:        str_names = strnames;
                    206:        separator = twidth ? ", " : ",";
                    207:        trailer = "\n\t";
                    208:        break;
                    209:
                    210:     case F_VARIABLE:
                    211:        bool_names = boolfnames;
                    212:        num_names = numfnames;
                    213:        str_names = strfnames;
                    214:        separator = twidth ? ", " : ",";
                    215:        trailer = "\n\t";
                    216:        break;
                    217:
                    218:     case F_TERMCAP:
                    219:     case F_TCONVERR:
                    220:        bool_names = boolcodes;
                    221:        num_names = numcodes;
                    222:        str_names = strcodes;
                    223:        separator = ":";
                    224:        trailer = "\\\n\t:";
                    225:        break;
                    226:     }
                    227:
                    228:     /* implement sort modes */
1.10      millert   229:     switch (sortmode = sort) {
1.1       millert   230:     case S_NOSORT:
                    231:        if (traceval)
                    232:            (void) fprintf(stderr,
1.19    ! nicm      233:                           "%s: sorting by term structure order\n", _nc_progname);
1.1       millert   234:        break;
                    235:
                    236:     case S_TERMINFO:
                    237:        if (traceval)
                    238:            (void) fprintf(stderr,
1.19    ! nicm      239:                           "%s: sorting by terminfo name order\n", _nc_progname);
1.1       millert   240:        bool_indirect = bool_terminfo_sort;
                    241:        num_indirect = num_terminfo_sort;
                    242:        str_indirect = str_terminfo_sort;
                    243:        break;
                    244:
                    245:     case S_VARIABLE:
                    246:        if (traceval)
                    247:            (void) fprintf(stderr,
1.19    ! nicm      248:                           "%s: sorting by C variable order\n", _nc_progname);
1.1       millert   249:        bool_indirect = bool_variable_sort;
                    250:        num_indirect = num_variable_sort;
                    251:        str_indirect = str_variable_sort;
                    252:        break;
                    253:
                    254:     case S_TERMCAP:
                    255:        if (traceval)
                    256:            (void) fprintf(stderr,
1.19    ! nicm      257:                           "%s: sorting by termcap name order\n", _nc_progname);
1.1       millert   258:        bool_indirect = bool_termcap_sort;
                    259:        num_indirect = num_termcap_sort;
                    260:        str_indirect = str_termcap_sort;
                    261:        break;
                    262:     }
                    263:
                    264:     if (traceval)
                    265:        (void) fprintf(stderr,
1.19    ! nicm      266:                       "%s: width = %d, tversion = %d, outform = %d\n",
        !           267:                       _nc_progname, width, tversion, outform);
1.1       millert   268: }
                    269:
1.10      millert   270: static TERMTYPE *cur_type;
1.1       millert   271:
1.10      millert   272: static int
1.19    ! nicm      273: dump_predicate(PredType type, PredIdx idx)
1.1       millert   274: /* predicate function to use for ordinary decompilation */
                    275: {
1.10      millert   276:     switch (type) {
                    277:     case BOOLEAN:
                    278:        return (cur_type->Booleans[idx] == FALSE)
                    279:            ? FAIL : cur_type->Booleans[idx];
1.1       millert   280:
1.10      millert   281:     case NUMBER:
                    282:        return (cur_type->Numbers[idx] == ABSENT_NUMERIC)
                    283:            ? FAIL : cur_type->Numbers[idx];
1.1       millert   284:
1.10      millert   285:     case STRING:
                    286:        return (cur_type->Strings[idx] != ABSENT_STRING)
                    287:            ? (int) TRUE : FAIL;
                    288:     }
1.1       millert   289:
1.10      millert   290:     return (FALSE);            /* pacify compiler */
1.1       millert   291: }
                    292:
1.19    ! nicm      293: static void set_obsolete_termcaps(TERMTYPE *tp);
1.1       millert   294:
                    295: /* is this the index of a function key string? */
                    296: #define FNKEY(i)       (((i)<= 65 && (i)>= 75) || ((i)<= 216 && (i)>= 268))
                    297:
1.19    ! nicm      298: /*
        !           299:  * If we configure with a different Caps file, the offsets into the arrays
        !           300:  * will change.  So we use an address expression.
        !           301:  */
        !           302: #define BOOL_IDX(name) (PredType) (&(name) - &(CUR Booleans[0]))
        !           303: #define NUM_IDX(name)  (PredType) (&(name) - &(CUR Numbers[0]))
        !           304: #define STR_IDX(name)  (PredType) (&(name) - &(CUR Strings[0]))
        !           305:
1.10      millert   306: static bool
1.19    ! nicm      307: version_filter(PredType type, PredIdx idx)
1.1       millert   308: /* filter out capabilities we may want to suppress */
                    309: {
1.10      millert   310:     switch (tversion) {
                    311:     case V_ALLCAPS:            /* SVr4, XSI Curses */
                    312:        return (TRUE);
                    313:
                    314:     case V_SVR1:               /* System V Release 1, Ultrix */
                    315:        switch (type) {
1.1       millert   316:        case BOOLEAN:
1.19    ! nicm      317:            return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
1.1       millert   318:        case NUMBER:
1.19    ! nicm      319:            return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
1.1       millert   320:        case STRING:
1.19    ! nicm      321:            return ((idx <= STR_IDX(prtr_non)) ? TRUE : FALSE);
1.1       millert   322:        }
                    323:        break;
                    324:
                    325:     case V_HPUX:               /* Hewlett-Packard */
1.10      millert   326:        switch (type) {
1.1       millert   327:        case BOOLEAN:
1.19    ! nicm      328:            return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
1.1       millert   329:        case NUMBER:
1.19    ! nicm      330:            return ((idx <= NUM_IDX(label_width)) ? TRUE : FALSE);
1.1       millert   331:        case STRING:
1.19    ! nicm      332:            if (idx <= STR_IDX(prtr_non))
1.10      millert   333:                return (TRUE);
1.1       millert   334:            else if (FNKEY(idx))        /* function keys */
1.10      millert   335:                return (TRUE);
1.19    ! nicm      336:            else if (idx == STR_IDX(plab_norm)
        !           337:                     || idx == STR_IDX(label_on)
        !           338:                     || idx == STR_IDX(label_off))
1.10      millert   339:                return (TRUE);
1.1       millert   340:            else
1.10      millert   341:                return (FALSE);
1.1       millert   342:        }
                    343:        break;
                    344:
                    345:     case V_AIX:                /* AIX */
1.10      millert   346:        switch (type) {
1.1       millert   347:        case BOOLEAN:
1.19    ! nicm      348:            return ((idx <= BOOL_IDX(xon_xoff)) ? TRUE : FALSE);
1.1       millert   349:        case NUMBER:
1.19    ! nicm      350:            return ((idx <= NUM_IDX(width_status_line)) ? TRUE : FALSE);
1.1       millert   351:        case STRING:
1.19    ! nicm      352:            if (idx <= STR_IDX(prtr_non))
1.10      millert   353:                return (TRUE);
1.1       millert   354:            else if (FNKEY(idx))        /* function keys */
1.10      millert   355:                return (TRUE);
1.1       millert   356:            else
1.10      millert   357:                return (FALSE);
1.1       millert   358:        }
                    359:        break;
                    360:
1.19    ! nicm      361: #define is_termcap(type) (OkIndex(idx, type##_from_termcap) && \
        !           362:                          type##_from_termcap[idx])
        !           363:
1.1       millert   364:     case V_BSD:                /* BSD */
1.10      millert   365:        switch (type) {
1.1       millert   366:        case BOOLEAN:
1.19    ! nicm      367:            return is_termcap(bool);
1.1       millert   368:        case NUMBER:
1.19    ! nicm      369:            return is_termcap(num);
1.1       millert   370:        case STRING:
1.19    ! nicm      371:            return is_termcap(str);
1.1       millert   372:        }
                    373:        break;
                    374:     }
                    375:
1.10      millert   376:     return (FALSE);            /* pacify the compiler */
1.1       millert   377: }
                    378:
1.11      millert   379: static void
1.19    ! nicm      380: trim_trailing(void)
        !           381: {
        !           382:     while (outbuf.used > 0 && outbuf.text[outbuf.used - 1] == ' ')
        !           383:        outbuf.text[--outbuf.used] = '\0';
        !           384: }
        !           385:
        !           386: static void
1.10      millert   387: force_wrap(void)
1.1       millert   388: {
1.10      millert   389:     oldcol = column;
1.19    ! nicm      390:     trim_trailing();
1.15      millert   391:     strcpy_DYN(&outbuf, trailer);
1.10      millert   392:     column = INDENT;
1.1       millert   393: }
                    394:
1.11      millert   395: static void
1.10      millert   396: wrap_concat(const char *src)
1.1       millert   397: {
1.19    ! nicm      398:     unsigned need = strlen(src);
        !           399:     unsigned want = strlen(separator) + need;
1.1       millert   400:
1.10      millert   401:     if (column > INDENT
1.19    ! nicm      402:        && column + (int) want > width) {
1.10      millert   403:        force_wrap();
                    404:     }
1.15      millert   405:     strcpy_DYN(&outbuf, src);
                    406:     strcpy_DYN(&outbuf, separator);
1.19    ! nicm      407:     column += (int) need;
1.1       millert   408: }
                    409:
                    410: #define IGNORE_SEP_TRAIL(first,last,sep_trail) \
                    411:        if ((size_t)(last - first) > sizeof(sep_trail)-1 \
                    412:         && !strncmp(first, sep_trail, sizeof(sep_trail)-1)) \
1.19    ! nicm      413:                first += sizeof(sep_trail)-2
1.1       millert   414:
                    415: /* Returns the nominal length of the buffer assuming it is termcap format,
                    416:  * i.e., the continuation sequence is treated as a single character ":".
                    417:  *
                    418:  * There are several implementations of termcap which read the text into a
                    419:  * fixed-size buffer.  Generally they strip the newlines from the text, but may
                    420:  * not do it until after the buffer is read.  Also, "tc=" resolution may be
                    421:  * expanded in the same buffer.  This function is useful for measuring the size
                    422:  * of the best fixed-buffer implementation; the worst case may be much worse.
                    423:  */
                    424: #ifdef TEST_TERMCAP_LENGTH
1.10      millert   425: static int
                    426: termcap_length(const char *src)
1.1       millert   427: {
1.10      millert   428:     static const char pattern[] = ":\\\n\t:";
1.1       millert   429:
1.10      millert   430:     int len = 0;
                    431:     const char *const t = src + strlen(src);
1.1       millert   432:
1.10      millert   433:     while (*src != '\0') {
                    434:        IGNORE_SEP_TRAIL(src, t, pattern);
                    435:        src++;
                    436:        len++;
                    437:     }
                    438:     return len;
1.1       millert   439: }
                    440: #else
                    441: #define termcap_length(src) strlen(src)
                    442: #endif
                    443:
1.19    ! nicm      444: static void
        !           445: indent_DYN(DYNBUF * buffer, int level)
        !           446: {
        !           447:     int n;
        !           448:
        !           449:     for (n = 0; n < level; n++)
        !           450:        strncpy_DYN(buffer, "\t", 1);
        !           451: }
        !           452:
        !           453: static bool
        !           454: has_params(const char *src)
        !           455: {
        !           456:     bool result = FALSE;
        !           457:     int len = (int) strlen(src);
        !           458:     int n;
        !           459:     bool ifthen = FALSE;
        !           460:     bool params = FALSE;
        !           461:
        !           462:     for (n = 0; n < len - 1; ++n) {
        !           463:        if (!strncmp(src + n, "%p", 2)) {
        !           464:            params = TRUE;
        !           465:        } else if (!strncmp(src + n, "%;", 2)) {
        !           466:            ifthen = TRUE;
        !           467:            result = params;
        !           468:            break;
        !           469:        }
        !           470:     }
        !           471:     if (!ifthen) {
        !           472:        result = ((len > 50) && params);
        !           473:     }
        !           474:     return result;
        !           475: }
        !           476:
1.10      millert   477: static char *
1.15      millert   478: fmt_complex(char *src, int level)
1.1       millert   479: {
1.19    ! nicm      480:     bool percent = FALSE;
        !           481:     bool params = has_params(src);
1.10      millert   482:
                    483:     while (*src != '\0') {
                    484:        switch (*src) {
                    485:        case '\\':
1.19    ! nicm      486:            percent = FALSE;
1.15      millert   487:            strncpy_DYN(&tmpbuf, src++, 1);
1.10      millert   488:            break;
                    489:        case '%':
1.19    ! nicm      490:            percent = TRUE;
1.10      millert   491:            break;
                    492:        case '?':               /* "if" */
                    493:        case 't':               /* "then" */
                    494:        case 'e':               /* "else" */
                    495:            if (percent) {
1.19    ! nicm      496:                percent = FALSE;
1.15      millert   497:                tmpbuf.text[tmpbuf.used - 1] = '\n';
1.19    ! nicm      498:                /* treat a "%e" as else-if, on the same level */
        !           499:                if (*src == 'e') {
        !           500:                    indent_DYN(&tmpbuf, level);
1.15      millert   501:                    strncpy_DYN(&tmpbuf, "%", 1);
1.19    ! nicm      502:                    strncpy_DYN(&tmpbuf, src, 1);
        !           503:                    src++;
        !           504:                    params = has_params(src);
        !           505:                    if (!params && *src != '\0' && *src != '%') {
        !           506:                        strncpy_DYN(&tmpbuf, "\n", 1);
        !           507:                        indent_DYN(&tmpbuf, level + 1);
        !           508:                    }
1.15      millert   509:                } else {
1.19    ! nicm      510:                    indent_DYN(&tmpbuf, level + 1);
1.15      millert   511:                    strncpy_DYN(&tmpbuf, "%", 1);
                    512:                    strncpy_DYN(&tmpbuf, src, 1);
                    513:                    if (*src++ == '?') {
                    514:                        src = fmt_complex(src, level + 1);
1.19    ! nicm      515:                        if (*src != '\0' && *src != '%') {
        !           516:                            strncpy_DYN(&tmpbuf, "\n", 1);
        !           517:                            indent_DYN(&tmpbuf, level + 1);
        !           518:                        }
1.15      millert   519:                    } else if (level == 1) {
                    520:                        _nc_warning("%%%c without %%?", *src);
                    521:                    }
1.10      millert   522:                }
                    523:                continue;
                    524:            }
                    525:            break;
                    526:        case ';':               /* "endif" */
                    527:            if (percent) {
1.19    ! nicm      528:                percent = FALSE;
1.10      millert   529:                if (level > 1) {
1.15      millert   530:                    tmpbuf.text[tmpbuf.used - 1] = '\n';
1.19    ! nicm      531:                    indent_DYN(&tmpbuf, level);
1.15      millert   532:                    strncpy_DYN(&tmpbuf, "%", 1);
                    533:                    strncpy_DYN(&tmpbuf, src++, 1);
1.10      millert   534:                    return src;
1.1       millert   535:                }
1.10      millert   536:                _nc_warning("%%; without %%?");
                    537:            }
                    538:            break;
                    539:        case 'p':
                    540:            if (percent && params) {
1.15      millert   541:                tmpbuf.text[tmpbuf.used - 1] = '\n';
1.19    ! nicm      542:                indent_DYN(&tmpbuf, level + 1);
1.15      millert   543:                strncpy_DYN(&tmpbuf, "%", 1);
1.10      millert   544:            }
1.19    ! nicm      545:            params = FALSE;
        !           546:            percent = FALSE;
1.10      millert   547:            break;
1.19    ! nicm      548:        case ' ':
        !           549:            strncpy_DYN(&tmpbuf, "\\s", 2);
        !           550:            ++src;
        !           551:            continue;
1.10      millert   552:        default:
1.19    ! nicm      553:            percent = FALSE;
1.10      millert   554:            break;
1.1       millert   555:        }
1.15      millert   556:        strncpy_DYN(&tmpbuf, src++, 1);
1.10      millert   557:     }
                    558:     return src;
1.1       millert   559: }
                    560:
1.19    ! nicm      561: #define SAME_CAP(n,cap) (&tterm->Strings[n] == &cap)
        !           562: #define EXTRA_CAP 20
        !           563:
1.10      millert   564: int
1.19    ! nicm      565: fmt_entry(TERMTYPE *tterm,
        !           566:          PredFunc pred,
        !           567:          bool content_only,
        !           568:          bool suppress_untranslatable,
        !           569:          bool infodump,
        !           570:          int numbers)
1.10      millert   571: {
1.19    ! nicm      572:     PredIdx i, j;
        !           573:     char buffer[MAX_TERMINFO_LENGTH + EXTRA_CAP];
        !           574:     char *capability;
1.10      millert   575:     NCURSES_CONST char *name;
                    576:     int predval, len;
1.19    ! nicm      577:     PredIdx num_bools = 0;
        !           578:     PredIdx num_values = 0;
        !           579:     PredIdx num_strings = 0;
1.10      millert   580:     bool outcount = 0;
1.1       millert   581:
                    582: #define WRAP_CONCAT    \
                    583:        wrap_concat(buffer); \
                    584:        outcount = TRUE
                    585:
                    586:     len = 12;                  /* terminfo file-header */
                    587:
                    588:     if (pred == 0) {
                    589:        cur_type = tterm;
                    590:        pred = dump_predicate;
                    591:     }
                    592:
1.15      millert   593:     strcpy_DYN(&outbuf, 0);
1.19    ! nicm      594:     if (content_only) {
        !           595:        column = INDENT;        /* FIXME: workaround to prevent empty lines */
        !           596:     } else {
        !           597:        strcpy_DYN(&outbuf, tterm->term_names);
        !           598:        strcpy_DYN(&outbuf, separator);
        !           599:        column = (int) outbuf.used;
        !           600:        force_wrap();
        !           601:     }
1.1       millert   602:
1.10      millert   603:     for_each_boolean(j, tterm) {
1.4       millert   604:        i = BoolIndirect(j);
1.10      millert   605:        name = ExtBoolname(tterm, i, bool_names);
1.19    ! nicm      606:        assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
1.1       millert   607:
                    608:        if (!version_filter(BOOLEAN, i))
                    609:            continue;
1.10      millert   610:        else if (isObsolete(outform, name))
1.1       millert   611:            continue;
                    612:
                    613:        predval = pred(BOOLEAN, i);
                    614:        if (predval != FAIL) {
1.17      deraadt   615:            (void) strlcpy(buffer, name, sizeof buffer);
1.1       millert   616:            if (predval <= 0)
1.17      deraadt   617:                (void) strlcat(buffer, "@", sizeof buffer);
1.1       millert   618:            else if (i + 1 > num_bools)
                    619:                num_bools = i + 1;
                    620:            WRAP_CONCAT;
                    621:        }
                    622:     }
                    623:
                    624:     if (column != INDENT)
                    625:        force_wrap();
                    626:
1.10      millert   627:     for_each_number(j, tterm) {
1.4       millert   628:        i = NumIndirect(j);
1.10      millert   629:        name = ExtNumname(tterm, i, num_names);
1.19    ! nicm      630:        assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
1.1       millert   631:
                    632:        if (!version_filter(NUMBER, i))
                    633:            continue;
1.10      millert   634:        else if (isObsolete(outform, name))
1.1       millert   635:            continue;
                    636:
                    637:        predval = pred(NUMBER, i);
                    638:        if (predval != FAIL) {
                    639:            if (tterm->Numbers[i] < 0) {
1.17      deraadt   640:                snprintf(buffer, sizeof buffer, "%s@", name);
1.1       millert   641:            } else {
1.17      deraadt   642:                snprintf(buffer, sizeof buffer, "%s#%d", name, tterm->Numbers[i]);
1.1       millert   643:                if (i + 1 > num_values)
                    644:                    num_values = i + 1;
                    645:            }
                    646:            WRAP_CONCAT;
                    647:        }
                    648:     }
                    649:
                    650:     if (column != INDENT)
                    651:        force_wrap();
                    652:
1.19    ! nicm      653:     len += (int) (num_bools
        !           654:                  + num_values * 2
        !           655:                  + strlen(tterm->term_names) + 1);
1.1       millert   656:     if (len & 1)
1.10      millert   657:        len++;
1.1       millert   658:
1.15      millert   659: #undef CUR
                    660: #define CUR tterm->
                    661:     if (outform == F_TERMCAP) {
                    662:        if (termcap_reset != ABSENT_STRING) {
                    663:            if (init_3string != ABSENT_STRING
                    664:                && !strcmp(init_3string, termcap_reset))
                    665:                DISCARD(init_3string);
                    666:
                    667:            if (reset_2string != ABSENT_STRING
                    668:                && !strcmp(reset_2string, termcap_reset))
                    669:                DISCARD(reset_2string);
                    670:        }
                    671:     }
                    672:
1.4       millert   673:     for_each_string(j, tterm) {
                    674:        i = StrIndirect(j);
1.10      millert   675:        name = ExtStrname(tterm, i, str_names);
1.19    ! nicm      676:        assert(strlen(name) < sizeof(buffer) - EXTRA_CAP);
        !           677:
        !           678:        capability = tterm->Strings[i];
1.1       millert   679:
                    680:        if (!version_filter(STRING, i))
                    681:            continue;
1.10      millert   682:        else if (isObsolete(outform, name))
1.1       millert   683:            continue;
                    684:
1.19    ! nicm      685: #if NCURSES_XNAMES
1.1       millert   686:        /*
1.19    ! nicm      687:         * Extended names can be longer than 2 characters, but termcap programs
        !           688:         * cannot read those (filter them out).
1.1       millert   689:         */
1.19    ! nicm      690:        if (outform == F_TERMCAP && (strlen(name) > 2))
        !           691:            continue;
        !           692: #endif
        !           693:
1.10      millert   694:        if (outform == F_TERMCAP) {
1.19    ! nicm      695:            /*
        !           696:             * Some older versions of vi want rmir/smir to be defined
        !           697:             * for ich/ich1 to work.  If they're not defined, force
        !           698:             * them to be output as defined and empty.
        !           699:             */
        !           700:            if (PRESENT(insert_character) || PRESENT(parm_ich)) {
        !           701:                if (SAME_CAP(i, enter_insert_mode)
1.10      millert   702:                    && enter_insert_mode == ABSENT_STRING) {
1.19    ! nicm      703:                    (void) strlcpy(buffer, "im=", sizeof(buffer));
1.15      millert   704:                    WRAP_CONCAT;
                    705:                    continue;
1.1       millert   706:                }
                    707:
1.19    ! nicm      708:                if (SAME_CAP(i, exit_insert_mode)
1.10      millert   709:                    && exit_insert_mode == ABSENT_STRING) {
1.19    ! nicm      710:                        (void) strlcpy(buffer, "ei=", sizeof(buffer));
1.15      millert   711:                    WRAP_CONCAT;
                    712:                    continue;
1.1       millert   713:                }
                    714:            }
1.19    ! nicm      715:            /*
        !           716:             * termcap applications such as screen will be confused if sgr0
        !           717:             * is translated to a string containing rmacs.  Filter that out.
        !           718:             */
        !           719:            if (PRESENT(exit_attribute_mode)) {
        !           720:                if (SAME_CAP(i, exit_attribute_mode)) {
        !           721:                    char *trimmed_sgr0;
        !           722:                    char *my_sgr = set_attributes;
        !           723:
        !           724:                    set_attributes = save_sgr;
        !           725:
        !           726:                    trimmed_sgr0 = _nc_trim_sgr0(tterm);
        !           727:                    if (strcmp(capability, trimmed_sgr0))
        !           728:                        capability = trimmed_sgr0;
        !           729:
        !           730:                    set_attributes = my_sgr;
        !           731:                }
        !           732:            }
1.2       millert   733:        }
                    734:
1.1       millert   735:        predval = pred(STRING, i);
                    736:        buffer[0] = '\0';
1.15      millert   737:
1.1       millert   738:        if (predval != FAIL) {
1.19    ! nicm      739:            if (capability != ABSENT_STRING
1.10      millert   740:                && i + 1 > num_strings)
1.1       millert   741:                num_strings = i + 1;
1.15      millert   742:
1.19    ! nicm      743:            if (!VALID_STRING(capability)) {
        !           744:                snprintf(buffer, sizeof(buffer), "%s@", name);
1.15      millert   745:                WRAP_CONCAT;
                    746:            } else if (outform == F_TERMCAP || outform == F_TCONVERR) {
1.19    ! nicm      747:                int params = ((i < (int) SIZEOF(parametrized))
        !           748:                              ? parametrized[i]
        !           749:                              : 0);
        !           750:                char *srccap = _nc_tic_expand(capability, TRUE, numbers);
1.16      millert   751:                char *cv = _nc_infotocap(name, srccap, params);
1.1       millert   752:
1.10      millert   753:                if (cv == 0) {
1.15      millert   754:                    if (outform == F_TCONVERR) {
1.19    ! nicm      755:                        snprintf(buffer, sizeof(buffer),
        !           756:                            "%s=!!! %s WILL NOT CONVERT !!!", name, srccap);
1.15      millert   757:                    } else if (suppress_untranslatable) {
1.1       millert   758:                        continue;
1.15      millert   759:                    } else {
1.18      millert   760:                        char *d, *s = srccap;
1.19    ! nicm      761:                        snprintf(buffer, sizeof(buffer), "..%s=", name);
1.17      deraadt   762:                        d = buffer + strlen(buffer);
1.19    ! nicm      763:                        while ((*d = *s++) != 0) {      /* XXX overflow */
1.10      millert   764:                            if (*d == ':') {
                    765:                                *d++ = '\\';
                    766:                                *d = ':';
                    767:                            } else if (*d == '\\') {
                    768:                                *++d = *s++;
                    769:                            }
                    770:                            d++;
                    771:                        }
                    772:                    }
1.15      millert   773:                } else {
1.17      deraadt   774:                    snprintf(buffer, sizeof buffer, "%s=%s", name, cv);
1.15      millert   775:                }
1.19    ! nicm      776:                len += (int) strlen(capability) + 1;
1.15      millert   777:                WRAP_CONCAT;
1.10      millert   778:            } else {
1.19    ! nicm      779:                char *src = _nc_tic_expand(capability,
        !           780:                                           outform == F_TERMINFO, numbers);
1.15      millert   781:
                    782:                strcpy_DYN(&tmpbuf, 0);
                    783:                strcpy_DYN(&tmpbuf, name);
                    784:                strcpy_DYN(&tmpbuf, "=");
1.8       millert   785:                if (pretty
1.10      millert   786:                    && (outform == F_TERMINFO
1.15      millert   787:                        || outform == F_VARIABLE)) {
                    788:                    fmt_complex(src, 1);
                    789:                } else {
                    790:                    strcpy_DYN(&tmpbuf, src);
                    791:                }
1.19    ! nicm      792:                len += (int) strlen(capability) + 1;
1.15      millert   793:                wrap_concat(tmpbuf.text);
                    794:                outcount = TRUE;
1.1       millert   795:            }
                    796:        }
1.19    ! nicm      797:        /* e.g., trimmed_sgr0 */
        !           798:        if (capability != tterm->Strings[i])
        !           799:            free(capability);
1.1       millert   800:     }
1.19    ! nicm      801:     len += (int) (num_strings * 2);
1.1       millert   802:
                    803:     /*
                    804:      * This piece of code should be an effective inverse of the functions
1.19    ! nicm      805:      * postprocess_terminfo() and postprocess_terminfo() in parse_entry.c.
1.1       millert   806:      * Much more work should be done on this to support dumping termcaps.
                    807:      */
1.10      millert   808:     if (tversion == V_HPUX) {
1.19    ! nicm      809:        if (VALID_STRING(memory_lock)) {
        !           810:            (void) snprintf(buffer, sizeof(buffer), "meml=%s", memory_lock);
1.1       millert   811:            WRAP_CONCAT;
                    812:        }
1.19    ! nicm      813:        if (VALID_STRING(memory_unlock)) {
        !           814:            (void) snprintf(buffer, sizeof(buffer), "memu=%s", memory_unlock);
1.1       millert   815:            WRAP_CONCAT;
                    816:        }
1.10      millert   817:     } else if (tversion == V_AIX) {
                    818:        if (VALID_STRING(acs_chars)) {
                    819:            bool box_ok = TRUE;
                    820:            const char *acstrans = "lqkxjmwuvtn";
                    821:            const char *cp;
                    822:            char *tp, *sp, boxchars[11];
1.1       millert   823:
                    824:            tp = boxchars;
1.10      millert   825:            for (cp = acstrans; *cp; cp++) {
1.1       millert   826:                sp = strchr(acs_chars, *cp);
                    827:                if (sp)
                    828:                    *tp++ = sp[1];
1.10      millert   829:                else {
1.1       millert   830:                    box_ok = FALSE;
                    831:                    break;
                    832:                }
                    833:            }
                    834:            tp[0] = '\0';
                    835:
1.10      millert   836:            if (box_ok) {
1.19    ! nicm      837:                (void) strlcpy(buffer, "box1=", sizeof(buffer));
1.17      deraadt   838:                (void) strlcat(buffer, _nc_tic_expand(boxchars,
1.19    ! nicm      839:                    outform == F_TERMINFO, numbers), sizeof(buffer));
1.1       millert   840:                WRAP_CONCAT;
                    841:            }
                    842:        }
                    843:     }
                    844:
                    845:     /*
                    846:      * kludge: trim off trailer to avoid an extra blank line
                    847:      * in infocmp -u output when there are no string differences
                    848:      */
1.10      millert   849:     if (outcount) {
1.15      millert   850:        bool trimmed = FALSE;
                    851:        j = outbuf.used;
1.1       millert   852:        if (j >= 2
1.15      millert   853:            && outbuf.text[j - 1] == '\t'
                    854:            && outbuf.text[j - 2] == '\n') {
                    855:            outbuf.used -= 2;
                    856:            trimmed = TRUE;
1.1       millert   857:        } else if (j >= 4
1.19    ! nicm      858:                   && outbuf.text[j - 1] == ':'
        !           859:                   && outbuf.text[j - 2] == '\t'
        !           860:                   && outbuf.text[j - 3] == '\n'
        !           861:                   && outbuf.text[j - 4] == '\\') {
1.15      millert   862:            outbuf.used -= 4;
                    863:            trimmed = TRUE;
                    864:        }
                    865:        if (trimmed) {
                    866:            outbuf.text[outbuf.used] = '\0';
                    867:            column = oldcol;
1.19    ! nicm      868:            strcpy_DYN(&outbuf, " ");
1.1       millert   869:        }
                    870:     }
                    871: #if 0
                    872:     fprintf(stderr, "num_bools = %d\n", num_bools);
                    873:     fprintf(stderr, "num_values = %d\n", num_values);
                    874:     fprintf(stderr, "num_strings = %d\n", num_strings);
                    875:     fprintf(stderr, "term_names=%s, len=%d, strlen(outbuf)=%d, outbuf=%s\n",
1.19    ! nicm      876:            tterm->term_names, len, outbuf.used, outbuf.text);
1.1       millert   877: #endif
                    878:     /*
                    879:      * Here's where we use infodump to trigger a more stringent length check
                    880:      * for termcap-translation purposes.
                    881:      * Return the length of the raw entry, without tc= expansions,
                    882:      * It gives an idea of which entries are deadly to even *scan past*,
                    883:      * as opposed to *use*.
                    884:      */
1.19    ! nicm      885:     return (infodump ? len : (int) termcap_length(outbuf.text));
        !           886: }
        !           887:
        !           888: static bool
        !           889: kill_string(TERMTYPE *tterm, char *cap)
        !           890: {
        !           891:     unsigned n;
        !           892:     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
        !           893:        if (cap == tterm->Strings[n]) {
        !           894:            tterm->Strings[n] = ABSENT_STRING;
        !           895:            return TRUE;
        !           896:        }
        !           897:     }
        !           898:     return FALSE;
1.1       millert   899: }
                    900:
1.19    ! nicm      901: static char *
        !           902: find_string(TERMTYPE *tterm, char *name)
        !           903: {
        !           904:     PredIdx n;
        !           905:     for (n = 0; n < NUM_STRINGS(tterm); ++n) {
        !           906:        if (version_filter(STRING, n)
        !           907:            && !strcmp(name, strnames[n])) {
        !           908:            char *cap = tterm->Strings[n];
        !           909:            if (VALID_STRING(cap)) {
        !           910:                return cap;
        !           911:            }
        !           912:            break;
        !           913:        }
        !           914:     }
        !           915:     return ABSENT_STRING;
        !           916: }
        !           917:
        !           918: /*
        !           919:  * This is used to remove function-key labels from a termcap entry to
        !           920:  * make it smaller.
        !           921:  */
        !           922: static int
        !           923: kill_labels(TERMTYPE *tterm, int target)
        !           924: {
        !           925:     int n;
        !           926:     int result = 0;
        !           927:     char *cap;
        !           928:     char name[10];
        !           929:
        !           930:     for (n = 0; n <= 10; ++n) {
        !           931:         snprintf(name, sizeof(name), "lf%d", n);
        !           932:        if ((cap = find_string(tterm, name)) != ABSENT_STRING
        !           933:            && kill_string(tterm, cap)) {
        !           934:            target -= (int) (strlen(cap) + 5);
        !           935:            ++result;
        !           936:            if (target < 0)
        !           937:                break;
        !           938:        }
        !           939:     }
        !           940:     return result;
        !           941: }
        !           942:
        !           943: /*
        !           944:  * This is used to remove function-key definitions from a termcap entry to
        !           945:  * make it smaller.
        !           946:  */
        !           947: static int
        !           948: kill_fkeys(TERMTYPE *tterm, int target)
        !           949: {
        !           950:     int n;
        !           951:     int result = 0;
        !           952:     char *cap;
        !           953:     char name[10];
        !           954:
        !           955:     for (n = 60; n >= 0; --n) {
        !           956:        snprintf(name, sizeof(name), "kf%d", n);
        !           957:        if ((cap = find_string(tterm, name)) != ABSENT_STRING
        !           958:            && kill_string(tterm, cap)) {
        !           959:            target -= (int) (strlen(cap) + 5);
        !           960:            ++result;
        !           961:            if (target < 0)
        !           962:                break;
        !           963:        }
        !           964:     }
        !           965:     return result;
        !           966: }
        !           967:
        !           968: /*
        !           969:  * Check if the given acsc string is a 1-1 mapping, i.e., just-like-vt100.
        !           970:  * Also, since this is for termcap, we only care about the line-drawing map.
        !           971:  */
        !           972: #define isLine(c) (strchr("lmkjtuvwqxn", c) != 0)
        !           973:
        !           974: static bool
        !           975: one_one_mapping(const char *mapping)
        !           976: {
        !           977:     bool result = TRUE;
        !           978:
        !           979:     if (mapping != ABSENT_STRING) {
        !           980:        int n = 0;
        !           981:        while (mapping[n] != '\0') {
        !           982:            if (isLine(mapping[n]) &&
        !           983:                mapping[n] != mapping[n + 1]) {
        !           984:                result = FALSE;
        !           985:                break;
        !           986:            }
        !           987:            n += 2;
        !           988:        }
        !           989:     }
        !           990:     return result;
        !           991: }
        !           992:
        !           993: #define FMT_ENTRY() \
        !           994:                fmt_entry(tterm, pred, \
        !           995:                        0, \
        !           996:                        suppress_untranslatable, \
        !           997:                        infodump, numbers)
        !           998:
        !           999: #define SHOW_WHY PRINTF
        !          1000:
        !          1001: static bool
        !          1002: purged_acs(TERMTYPE *tterm)
        !          1003: {
        !          1004:     bool result = FALSE;
        !          1005:
        !          1006:     if (VALID_STRING(acs_chars)) {
        !          1007:        if (!one_one_mapping(acs_chars)) {
        !          1008:            enter_alt_charset_mode = ABSENT_STRING;
        !          1009:            exit_alt_charset_mode = ABSENT_STRING;
        !          1010:            SHOW_WHY("# (rmacs/smacs removed for consistency)\n");
        !          1011:        }
        !          1012:        result = TRUE;
        !          1013:     }
        !          1014:     return result;
        !          1015: }
        !          1016:
        !          1017: /*
        !          1018:  * Dump a single entry.
        !          1019:  */
        !          1020: void
        !          1021: dump_entry(TERMTYPE *tterm,
        !          1022:           bool suppress_untranslatable,
        !          1023:           bool limited,
        !          1024:           int numbers,
        !          1025:           PredFunc pred)
1.1       millert  1026: {
1.19    ! nicm     1027:     TERMTYPE save_tterm;
1.10      millert  1028:     int len, critlen;
                   1029:     const char *legend;
                   1030:     bool infodump;
1.1       millert  1031:
1.10      millert  1032:     if (outform == F_TERMCAP || outform == F_TCONVERR) {
1.1       millert  1033:        critlen = MAX_TERMCAP_LENGTH;
                   1034:        legend = "older termcap";
                   1035:        infodump = FALSE;
                   1036:        set_obsolete_termcaps(tterm);
1.10      millert  1037:     } else {
1.1       millert  1038:        critlen = MAX_TERMINFO_LENGTH;
                   1039:        legend = "terminfo";
                   1040:        infodump = TRUE;
                   1041:     }
                   1042:
1.19    ! nicm     1043:     save_sgr = set_attributes;
        !          1044:
        !          1045:     if (((len = FMT_ENTRY()) > critlen)
1.10      millert  1046:        && limited) {
1.19    ! nicm     1047:
        !          1048:        save_tterm = *tterm;
        !          1049:        if (!suppress_untranslatable) {
        !          1050:            SHOW_WHY("# (untranslatable capabilities removed to fit entry within %d bytes)\n",
        !          1051:                     critlen);
        !          1052:            suppress_untranslatable = TRUE;
        !          1053:        }
        !          1054:        if ((len = FMT_ENTRY()) > critlen) {
1.1       millert  1055:            /*
                   1056:             * We pick on sgr because it's a nice long string capability that
1.12      millert  1057:             * is really just an optimization hack.  Another good candidate is
                   1058:             * acsc since it is both long and unused by BSD termcap.
1.1       millert  1059:             */
1.19    ! nicm     1060:            bool changed = FALSE;
        !          1061:
        !          1062: #if NCURSES_XNAMES
        !          1063:            /*
        !          1064:             * Extended names are most likely function-key definitions.  Drop
        !          1065:             * those first.
        !          1066:             */
        !          1067:            unsigned n;
        !          1068:            for (n = STRCOUNT; n < NUM_STRINGS(tterm); n++) {
        !          1069:                const char *name = ExtStrname(tterm, n, strnames);
        !          1070:
        !          1071:                if (VALID_STRING(tterm->Strings[n])) {
        !          1072:                    set_attributes = ABSENT_STRING;
        !          1073:                    /* we remove long names anyway - only report the short */
        !          1074:                    if (strlen(name) <= 2) {
        !          1075:                        SHOW_WHY("# (%s removed to fit entry within %d bytes)\n",
        !          1076:                                 name,
        !          1077:                                 critlen);
        !          1078:                    }
        !          1079:                    changed = TRUE;
        !          1080:                    if ((len = FMT_ENTRY()) <= critlen)
        !          1081:                        break;
        !          1082:                }
1.12      millert  1083:            }
1.19    ! nicm     1084: #endif
        !          1085:            if (VALID_STRING(set_attributes)) {
        !          1086:                set_attributes = ABSENT_STRING;
        !          1087:                SHOW_WHY("# (sgr removed to fit entry within %d bytes)\n",
        !          1088:                         critlen);
        !          1089:                changed = TRUE;
        !          1090:            }
        !          1091:            if (!changed || ((len = FMT_ENTRY()) > critlen)) {
        !          1092:                if (purged_acs(tterm)) {
        !          1093:                    acs_chars = ABSENT_STRING;
        !          1094:                    SHOW_WHY("# (acsc removed to fit entry within %d bytes)\n",
        !          1095:                             critlen);
        !          1096:                    changed = TRUE;
        !          1097:                }
        !          1098:            }
        !          1099:            if (!changed || ((len = FMT_ENTRY()) > critlen)) {
1.1       millert  1100:                int oldversion = tversion;
                   1101:
                   1102:                tversion = V_BSD;
1.19    ! nicm     1103:                SHOW_WHY("# (terminfo-only capabilities suppressed to fit entry within %d bytes)\n",
        !          1104:                         critlen);
1.1       millert  1105:
1.19    ! nicm     1106:                len = FMT_ENTRY();
        !          1107:                if (len > critlen
        !          1108:                    && kill_labels(tterm, len - critlen)) {
        !          1109:                    SHOW_WHY("# (some labels capabilities suppressed to fit entry within %d bytes)\n",
        !          1110:                             critlen);
        !          1111:                    len = FMT_ENTRY();
        !          1112:                }
        !          1113:                if (len > critlen
        !          1114:                    && kill_fkeys(tterm, len - critlen)) {
        !          1115:                    SHOW_WHY("# (some function-key capabilities suppressed to fit entry within %d bytes)\n",
        !          1116:                             critlen);
        !          1117:                    len = FMT_ENTRY();
        !          1118:                }
        !          1119:                if (len > critlen) {
1.1       millert  1120:                    (void) fprintf(stderr,
1.19    ! nicm     1121:                                   "warning: %s entry is %d bytes long\n",
        !          1122:                                   _nc_first_name(tterm->term_names),
        !          1123:                                   len);
        !          1124:                    SHOW_WHY("# WARNING: this entry, %d bytes long, may core-dump %s libraries!\n",
        !          1125:                             len, legend);
1.1       millert  1126:                }
                   1127:                tversion = oldversion;
                   1128:            }
1.19    ! nicm     1129:            set_attributes = save_sgr;
        !          1130:            *tterm = save_tterm;
        !          1131:        }
        !          1132:     } else if (!version_filter(STRING, STR_IDX(acs_chars))) {
        !          1133:        save_tterm = *tterm;
        !          1134:        if (purged_acs(tterm)) {
        !          1135:            len = FMT_ENTRY();
1.1       millert  1136:        }
1.19    ! nicm     1137:        *tterm = save_tterm;
1.1       millert  1138:     }
                   1139: }
                   1140:
1.19    ! nicm     1141: void
1.10      millert  1142: dump_uses(const char *name, bool infodump)
1.1       millert  1143: /* dump "use=" clauses in the appropriate format */
                   1144: {
                   1145:     char buffer[MAX_TERMINFO_LENGTH];
                   1146:
1.19    ! nicm     1147:     if (outform == F_TERMCAP || outform == F_TCONVERR)
        !          1148:        trim_trailing();
        !          1149:     (void) snprintf(buffer, sizeof(buffer), "%s%s", infodump ? "use=" : "tc=",
        !          1150:        name);
1.1       millert  1151:     wrap_concat(buffer);
1.19    ! nicm     1152: }
        !          1153:
        !          1154: int
        !          1155: show_entry(void)
        !          1156: {
        !          1157:     trim_trailing();
1.15      millert  1158:     (void) fputs(outbuf.text, stdout);
1.19    ! nicm     1159:     putchar('\n');
        !          1160:     return (int) outbuf.used;
1.1       millert  1161: }
                   1162:
1.10      millert  1163: void
1.19    ! nicm     1164: compare_entry(void (*hook) (PredType t, PredIdx i, const char *name),
        !          1165:              TERMTYPE *tp GCC_UNUSED,
        !          1166:              bool quiet)
1.1       millert  1167: /* compare two entries */
                   1168: {
1.19    ! nicm     1169:     PredIdx i, j;
1.10      millert  1170:     NCURSES_CONST char *name;
1.1       millert  1171:
1.15      millert  1172:     if (!quiet)
                   1173:        fputs("    comparing booleans.\n", stdout);
1.10      millert  1174:     for_each_boolean(j, tp) {
1.4       millert  1175:        i = BoolIndirect(j);
1.10      millert  1176:        name = ExtBoolname(tp, i, bool_names);
1.1       millert  1177:
1.10      millert  1178:        if (isObsolete(outform, name))
1.1       millert  1179:            continue;
                   1180:
1.14      millert  1181:        (*hook) (CMP_BOOLEAN, i, name);
1.1       millert  1182:     }
                   1183:
1.15      millert  1184:     if (!quiet)
                   1185:        fputs("    comparing numbers.\n", stdout);
1.10      millert  1186:     for_each_number(j, tp) {
1.4       millert  1187:        i = NumIndirect(j);
1.10      millert  1188:        name = ExtNumname(tp, i, num_names);
1.1       millert  1189:
1.10      millert  1190:        if (isObsolete(outform, name))
1.1       millert  1191:            continue;
                   1192:
1.14      millert  1193:        (*hook) (CMP_NUMBER, i, name);
1.1       millert  1194:     }
                   1195:
1.15      millert  1196:     if (!quiet)
                   1197:        fputs("    comparing strings.\n", stdout);
1.10      millert  1198:     for_each_string(j, tp) {
1.4       millert  1199:        i = StrIndirect(j);
1.10      millert  1200:        name = ExtStrname(tp, i, str_names);
1.1       millert  1201:
1.10      millert  1202:        if (isObsolete(outform, name))
1.1       millert  1203:            continue;
                   1204:
1.14      millert  1205:        (*hook) (CMP_STRING, i, name);
1.1       millert  1206:     }
1.14      millert  1207:
                   1208:     /* (void) fputs("    comparing use entries.\n", stdout); */
                   1209:     (*hook) (CMP_USE, 0, "use");
                   1210:
1.1       millert  1211: }
                   1212:
                   1213: #define NOTSET(s)      ((s) == 0)
                   1214:
                   1215: /*
                   1216:  * This bit of legerdemain turns all the terminfo variable names into
                   1217:  * references to locations in the arrays Booleans, Numbers, and Strings ---
                   1218:  * precisely what's needed.
                   1219:  */
                   1220: #undef CUR
                   1221: #define CUR tp->
                   1222:
1.10      millert  1223: static void
1.19    ! nicm     1224: set_obsolete_termcaps(TERMTYPE *tp)
1.1       millert  1225: {
                   1226: #include "capdefaults.c"
                   1227: }
                   1228:
                   1229: /*
                   1230:  * Convert an alternate-character-set string to canonical form: sorted and
                   1231:  * unique.
                   1232:  */
1.14      millert  1233: void
1.19    ! nicm     1234: repair_acsc(TERMTYPE *tp)
1.1       millert  1235: {
1.10      millert  1236:     if (VALID_STRING(acs_chars)) {
                   1237:        size_t n, m;
                   1238:        char mapped[256];
                   1239:        char extra = 0;
                   1240:        unsigned source;
                   1241:        unsigned target;
                   1242:        bool fix_needed = FALSE;
                   1243:
                   1244:        for (n = 0, source = 0; acs_chars[n] != 0; n++) {
1.19    ! nicm     1245:            target = UChar(acs_chars[n]);
1.10      millert  1246:            if (source >= target) {
                   1247:                fix_needed = TRUE;
                   1248:                break;
                   1249:            }
                   1250:            source = target;
                   1251:            if (acs_chars[n + 1])
                   1252:                n++;
                   1253:        }
                   1254:        if (fix_needed) {
                   1255:            memset(mapped, 0, sizeof(mapped));
                   1256:            for (n = 0; acs_chars[n] != 0; n++) {
1.19    ! nicm     1257:                source = UChar(acs_chars[n]);
1.10      millert  1258:                if ((target = (unsigned char) acs_chars[n + 1]) != 0) {
1.19    ! nicm     1259:                    mapped[source] = (char) target;
1.10      millert  1260:                    n++;
                   1261:                } else {
1.19    ! nicm     1262:                    extra = (char) source;
1.1       millert  1263:                }
                   1264:            }
1.10      millert  1265:            for (n = m = 0; n < sizeof(mapped); n++) {
                   1266:                if (mapped[n]) {
1.19    ! nicm     1267:                    acs_chars[m++] = (char) n;
1.10      millert  1268:                    acs_chars[m++] = mapped[n];
1.1       millert  1269:                }
                   1270:            }
1.10      millert  1271:            if (extra)
                   1272:                acs_chars[m++] = extra;         /* garbage in, garbage out */
                   1273:            acs_chars[m] = 0;
1.1       millert  1274:        }
1.10      millert  1275:     }
1.1       millert  1276: }