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

Annotation of src/usr.bin/infocmp/infocmp.c, Revision 1.24

1.24    ! nicm        1: /*     $OpenBSD: infocmp.c,v 1.23 2016/08/03 16:32:08 krw Exp $        */
1.1       millert     2:
                      3: /****************************************************************************
1.24    ! nicm        4:  * Copyright 2020-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.20      nicm       35:  *     and: Thomas E. Dickey                        1996-on                 *
1.1       millert    36:  ****************************************************************************/
                     37:
                     38: /*
                     39:  *     infocmp.c -- decompile an entry, or compare two entries
                     40:  *             written by Eric S. Raymond
1.20      nicm       41:  *             and Thomas E Dickey
1.1       millert    42:  */
                     43:
                     44: #include <progs.priv.h>
                     45:
                     46: #include <dump_entry.h>
                     47:
1.24    ! nicm       48: MODULE_ID("$Id: infocmp.c,v 1.23 2016/08/03 16:32:08 krw Exp $")
1.1       millert    49:
1.9       millert    50: #define MAX_STRING     1024    /* maximum formatted string */
1.1       millert    51:
                     52: const char *_nc_progname = "infocmp";
                     53:
1.8       millert    54: typedef char path[PATH_MAX];
1.1       millert    55:
                     56: /***************************************************************************
                     57:  *
                     58:  * The following control variables, together with the contents of the
                     59:  * terminfo entries, completely determine the actions of the program.
                     60:  *
                     61:  ***************************************************************************/
                     62:
1.20      nicm       63: static ENTRY *entries;         /* terminfo entries */
1.1       millert    64: static int termcount;          /* count of terminal entries */
                     65:
1.9       millert    66: static bool limited = TRUE;    /* "-r" option is not set */
                     67: static bool quiet = FALSE;
1.20      nicm       68: static bool literal = FALSE;
1.10      millert    69: static const char *bool_sep = ":";
                     70: static const char *s_absent = "NULL";
                     71: static const char *s_cancel = "NULL";
1.1       millert    72: static const char *tversion;   /* terminfo version selected */
1.24    ! nicm       73: static unsigned itrace;                /* trace flag for debugging */
1.9       millert    74: static int mwidth = 60;
1.24    ! nicm       75: static int mheight = 65535;
1.3       millert    76: static int numbers = 0;                /* format "%'char'" to/from "%{number}" */
1.11      millert    77: static int outform = F_TERMINFO;       /* output format */
1.1       millert    78: static int sortmode;           /* sort_mode */
                     79:
                     80: /* main comparison mode */
                     81: static int compare;
                     82: #define C_DEFAULT      0       /* don't force comparison mode */
                     83: #define C_DIFFERENCE   1       /* list differences between two terminals */
                     84: #define C_COMMON       2       /* list common capabilities */
                     85: #define C_NAND         3       /* list capabilities in neither terminal */
                     86: #define C_USEALL       4       /* generate relative use-form entry */
                     87: static bool ignorepads;                /* ignore pad prefixes when diffing */
                     88:
                     89: #if NO_LEAKS
1.24    ! nicm       90:
        !            91: typedef struct {
        !            92:     ENTRY *head;
        !            93:     ENTRY *tail;
        !            94: } ENTERED;
        !            95:
        !            96: static ENTERED *entered;
        !            97:
1.1       millert    98: #undef ExitProgram
1.24    ! nicm       99: static GCC_NORETURN void ExitProgram(int code);
1.20      nicm      100: /* prototype is to get gcc to accept the noreturn attribute */
1.8       millert   101: static void
1.20      nicm      102: ExitProgram(int code)
1.1       millert   103: {
1.24    ! nicm      104:     int n;
        !           105:
        !           106:     for (n = 0; n < termcount; ++n) {
        !           107:        ENTRY *new_head = _nc_head;
        !           108:        ENTRY *new_tail = _nc_tail;
        !           109:        _nc_head = entered[n].head;
        !           110:        _nc_tail = entered[n].tail;
        !           111:        _nc_free_entries(entered[n].head);
        !           112:        _nc_head = new_head;
        !           113:        _nc_tail = new_tail;
        !           114:     }
1.8       millert   115:     _nc_leaks_dump_entry();
1.20      nicm      116:     free(entries);
1.24    ! nicm      117:     free(entered);
1.20      nicm      118:     _nc_free_tic(code);
1.1       millert   119: }
                    120: #endif
                    121:
1.24    ! nicm      122: static void
        !           123: failed(const char *s)
        !           124: {
        !           125:     perror(s);
        !           126:     ExitProgram(EXIT_FAILURE);
        !           127: }
        !           128:
        !           129: static void
        !           130: canonical_name(char *source, char *target)
1.1       millert   131: /* extract the terminal type's primary name */
                    132: {
1.24    ! nicm      133:     int limit = NAMESIZE;
1.1       millert   134:
1.24    ! nicm      135:     while (--limit > 0) {
        !           136:        char ch = *source++;
        !           137:        if (ch == '|')
        !           138:            break;
        !           139:        *target++ = ch;
        !           140:     }
        !           141:     *target = '\0';
        !           142: }
1.1       millert   143:
1.24    ! nicm      144: static bool
        !           145: no_boolean(int value)
        !           146: {
        !           147:     bool result = (value == ABSENT_BOOLEAN);
        !           148:     if (!strcmp(s_absent, s_cancel))
        !           149:        result = !VALID_BOOLEAN(value);
        !           150:     return result;
        !           151: }
        !           152:
        !           153: static bool
        !           154: no_numeric(int value)
        !           155: {
        !           156:     bool result = (value == ABSENT_NUMERIC);
        !           157:     if (!strcmp(s_absent, s_cancel))
        !           158:        result = !VALID_NUMERIC(value);
        !           159:     return result;
        !           160: }
        !           161:
        !           162: static bool
        !           163: no_string(const char *const value)
        !           164: {
        !           165:     bool result = (value == ABSENT_STRING);
        !           166:     if (!strcmp(s_absent, s_cancel))
        !           167:        result = !VALID_STRING(value);
        !           168:     return result;
1.1       millert   169: }
                    170:
                    171: /***************************************************************************
                    172:  *
                    173:  * Predicates for dump function
                    174:  *
                    175:  ***************************************************************************/
                    176:
1.8       millert   177: static int
1.20      nicm      178: capcmp(PredIdx idx, const char *s, const char *t)
1.1       millert   179: /* capability comparison function */
                    180: {
                    181:     if (!VALID_STRING(s) && !VALID_STRING(t))
1.9       millert   182:        return (s != t);
1.1       millert   183:     else if (!VALID_STRING(s) || !VALID_STRING(t))
1.8       millert   184:        return (1);
1.1       millert   185:
1.9       millert   186:     if ((idx == acs_chars_index) || !ignorepads)
                    187:        return (strcmp(s, t));
                    188:     else
1.8       millert   189:        return (_nc_capcmp(s, t));
1.1       millert   190: }
                    191:
1.8       millert   192: static int
1.20      nicm      193: use_predicate(unsigned type, PredIdx idx)
1.1       millert   194: /* predicate function to use for use decompilation */
                    195: {
1.9       millert   196:     ENTRY *ep;
1.1       millert   197:
1.8       millert   198:     switch (type) {
1.9       millert   199:     case BOOLEAN:
                    200:        {
1.8       millert   201:            int is_set = FALSE;
1.1       millert   202:
1.8       millert   203:            /*
                    204:             * This assumes that multiple use entries are supposed
                    205:             * to contribute the logical or of their boolean capabilities.
                    206:             * This is true if we take the semantics of multiple uses to
                    207:             * be 'each capability gets the first non-default value found
                    208:             * in the sequence of use entries'.
1.9       millert   209:             *
                    210:             * Note that cancelled or absent booleans are stored as FALSE,
                    211:             * unlike numbers and strings, whose cancelled/absent state is
                    212:             * recorded in the terminfo database.
1.8       millert   213:             */
1.9       millert   214:            for (ep = &entries[1]; ep < entries + termcount; ep++)
                    215:                if (ep->tterm.Booleans[idx] == TRUE) {
                    216:                    is_set = entries[0].tterm.Booleans[idx];
1.8       millert   217:                    break;
1.1       millert   218:                }
1.9       millert   219:            if (is_set != entries[0].tterm.Booleans[idx])
1.8       millert   220:                return (!is_set);
                    221:            else
                    222:                return (FAIL);
                    223:        }
1.1       millert   224:
1.9       millert   225:     case NUMBER:
                    226:        {
1.8       millert   227:            int value = ABSENT_NUMERIC;
1.1       millert   228:
1.8       millert   229:            /*
                    230:             * We take the semantics of multiple uses to be 'each
                    231:             * capability gets the first non-default value found
                    232:             * in the sequence of use entries'.
                    233:             */
1.9       millert   234:            for (ep = &entries[1]; ep < entries + termcount; ep++)
                    235:                if (VALID_NUMERIC(ep->tterm.Numbers[idx])) {
                    236:                    value = ep->tterm.Numbers[idx];
1.8       millert   237:                    break;
1.1       millert   238:                }
                    239:
1.9       millert   240:            if (value != entries[0].tterm.Numbers[idx])
1.8       millert   241:                return (value != ABSENT_NUMERIC);
                    242:            else
                    243:                return (FAIL);
                    244:        }
                    245:
1.9       millert   246:     case STRING:
                    247:        {
1.8       millert   248:            char *termstr, *usestr = ABSENT_STRING;
1.1       millert   249:
1.9       millert   250:            termstr = entries[0].tterm.Strings[idx];
1.1       millert   251:
1.8       millert   252:            /*
                    253:             * We take the semantics of multiple uses to be 'each
                    254:             * capability gets the first non-default value found
                    255:             * in the sequence of use entries'.
                    256:             */
1.9       millert   257:            for (ep = &entries[1]; ep < entries + termcount; ep++)
                    258:                if (ep->tterm.Strings[idx]) {
                    259:                    usestr = ep->tterm.Strings[idx];
1.8       millert   260:                    break;
                    261:                }
                    262:
                    263:            if (usestr == ABSENT_STRING && termstr == ABSENT_STRING)
                    264:                return (FAIL);
1.9       millert   265:            else if (!usestr || !termstr || capcmp(idx, usestr, termstr))
1.8       millert   266:                return (TRUE);
                    267:            else
                    268:                return (FAIL);
1.1       millert   269:        }
1.8       millert   270:     }
1.1       millert   271:
1.8       millert   272:     return (FALSE);            /* pacify compiler */
1.1       millert   273: }
                    274:
1.8       millert   275: static bool
1.9       millert   276: useeq(ENTRY * e1, ENTRY * e2)
                    277: /* are the use references in two entries equivalent? */
                    278: {
1.20      nicm      279:     unsigned i, j;
1.9       millert   280:
                    281:     if (e1->nuses != e2->nuses)
                    282:        return (FALSE);
                    283:
                    284:     /* Ugh...this is quadratic again */
                    285:     for (i = 0; i < e1->nuses; i++) {
                    286:        bool foundmatch = FALSE;
                    287:
                    288:        /* search second entry for given use reference */
                    289:        for (j = 0; j < e2->nuses; j++)
                    290:            if (!strcmp(e1->uses[i].name, e2->uses[j].name)) {
                    291:                foundmatch = TRUE;
                    292:                break;
                    293:            }
                    294:
                    295:        if (!foundmatch)
                    296:            return (FALSE);
                    297:     }
                    298:
                    299:     return (TRUE);
                    300: }
                    301:
                    302: static bool
1.24    ! nicm      303: entryeq(TERMTYPE2 *t1, TERMTYPE2 *t2)
1.9       millert   304: /* are two entries equivalent? */
1.1       millert   305: {
1.20      nicm      306:     unsigned i;
1.1       millert   307:
1.2       millert   308:     for (i = 0; i < NUM_BOOLEANS(t1); i++)
1.1       millert   309:        if (t1->Booleans[i] != t2->Booleans[i])
1.8       millert   310:            return (FALSE);
1.1       millert   311:
1.2       millert   312:     for (i = 0; i < NUM_NUMBERS(t1); i++)
1.1       millert   313:        if (t1->Numbers[i] != t2->Numbers[i])
1.8       millert   314:            return (FALSE);
1.1       millert   315:
1.2       millert   316:     for (i = 0; i < NUM_STRINGS(t1); i++)
1.20      nicm      317:        if (capcmp((PredIdx) i, t1->Strings[i], t2->Strings[i]))
1.8       millert   318:            return (FALSE);
1.1       millert   319:
1.8       millert   320:     return (TRUE);
1.1       millert   321: }
                    322:
                    323: #define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers)
                    324:
1.8       millert   325: static void
1.20      nicm      326: print_uses(ENTRY * ep, FILE *fp)
1.9       millert   327: /* print an entry's use references */
                    328: {
1.24    ! nicm      329:     if (!ep->nuses) {
        !           330:        fputs("NULL", fp);
        !           331:     } else {
        !           332:        unsigned i;
1.9       millert   333:
                    334:        for (i = 0; i < ep->nuses; i++) {
                    335:            fputs(ep->uses[i].name, fp);
                    336:            if (i < ep->nuses - 1)
                    337:                fputs(" ", fp);
                    338:        }
1.24    ! nicm      339:     }
1.9       millert   340: }
                    341:
1.10      millert   342: static const char *
1.9       millert   343: dump_boolean(int val)
                    344: /* display the value of a boolean capability */
                    345: {
                    346:     switch (val) {
                    347:     case ABSENT_BOOLEAN:
                    348:        return (s_absent);
                    349:     case CANCELLED_BOOLEAN:
                    350:        return (s_cancel);
                    351:     case FALSE:
                    352:        return ("F");
                    353:     case TRUE:
                    354:        return ("T");
                    355:     default:
                    356:        return ("?");
                    357:     }
                    358: }
                    359:
                    360: static void
1.24    ! nicm      361: dump_numeric(int val, char *buf)
        !           362: /* display the value of a numeric capability */
1.9       millert   363: {
                    364:     switch (val) {
                    365:     case ABSENT_NUMERIC:
1.24    ! nicm      366:        _nc_STRCPY(buf, s_absent, MAX_STRING);
1.9       millert   367:        break;
                    368:     case CANCELLED_NUMERIC:
1.24    ! nicm      369:        _nc_STRCPY(buf, s_cancel, MAX_STRING);
1.9       millert   370:        break;
                    371:     default:
1.24    ! nicm      372:        _nc_SPRINTF(buf, _nc_SLIMIT(MAX_STRING) "%d", val);
1.9       millert   373:        break;
                    374:     }
                    375: }
                    376:
                    377: static void
1.24    ! nicm      378: dump_string(char *val, char *buf)
1.9       millert   379: /* display the value of a string capability */
                    380: {
                    381:     if (val == ABSENT_STRING)
1.24    ! nicm      382:        _nc_STRCPY(buf, s_absent, MAX_STRING);
1.9       millert   383:     else if (val == CANCELLED_STRING)
1.24    ! nicm      384:        _nc_STRCPY(buf, s_cancel, MAX_STRING);
1.9       millert   385:     else {
1.24    ! nicm      386:        _nc_SPRINTF(buf, _nc_SLIMIT(MAX_STRING)
        !           387:                    "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val));
1.9       millert   388:     }
                    389: }
                    390:
1.24    ! nicm      391: /*
        !           392:  * Show "comparing..." message for the given terminal names.
        !           393:  */
        !           394: static void
        !           395: show_comparing(char **names)
        !           396: {
        !           397:     if (itrace) {
        !           398:        switch (compare) {
        !           399:        case C_DIFFERENCE:
        !           400:            (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname);
        !           401:            break;
        !           402:
        !           403:        case C_COMMON:
        !           404:            (void) fprintf(stderr, "%s: dumping common capabilities\n", _nc_progname);
        !           405:            break;
        !           406:
        !           407:        case C_NAND:
        !           408:            (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname);
        !           409:            break;
        !           410:        }
        !           411:     }
        !           412:     if (*names) {
        !           413:        printf("comparing %s", *names++);
        !           414:        if (*names) {
        !           415:            printf(" to %s", *names++);
        !           416:            while (*names) {
        !           417:                printf(", %s", *names++);
        !           418:            }
        !           419:        }
        !           420:        printf(".\n");
        !           421:     }
        !           422: }
        !           423:
        !           424: /*
        !           425:  * ncurses stores two types of non-standard capabilities:
        !           426:  * a) capabilities listed past the "STOP-HERE" comment in the Caps file.
        !           427:  *    These are used in the terminfo source file to provide data for termcaps,
        !           428:  *    e.g., when there is no equivalent capability in terminfo, as well as for
        !           429:  *    widely-used non-standard capabilities.
        !           430:  * b) user-definable capabilities, via "tic -x".
        !           431:  *
        !           432:  * However, if "-x" is omitted from the tic command, both types of
        !           433:  * non-standard capability are not loaded into the terminfo database.  This
        !           434:  * macro is used for limit-checks against the symbols that tic uses to omit
        !           435:  * the two types of non-standard entry.
        !           436:  */
        !           437: #if NCURSES_XNAMES
        !           438: #define check_user_definable(n,limit) if (!_nc_user_definable && (n) > (limit)) break
        !           439: #else
        !           440: #define check_user_definable(n,limit) if ((n) > (limit)) break
        !           441: #endif
        !           442:
        !           443: /*
        !           444:  * Use these macros to simplify loops on C_COMMON and C_NAND:
        !           445:  */
        !           446: #define for_each_entry() while (entries[extra].tterm.term_names)
        !           447: #define next_entry           (&(entries[extra++].tterm))
        !           448:
1.9       millert   449: static void
1.20      nicm      450: compare_predicate(PredType type, PredIdx idx, const char *name)
1.1       millert   451: /* predicate function to use for entry difference reports */
                    452: {
1.15      mpech     453:     ENTRY *e1 = &entries[0];
                    454:     ENTRY *e2 = &entries[1];
1.24    ! nicm      455:     char buf1[MAX_STRING];
        !           456:     char buf2[MAX_STRING];
1.9       millert   457:     int b1, b2;
                    458:     int n1, n2;
1.8       millert   459:     char *s1, *s2;
1.24    ! nicm      460:     bool found;
        !           461:     int extra = 1;
1.8       millert   462:
                    463:     switch (type) {
1.9       millert   464:     case CMP_BOOLEAN:
1.24    ! nicm      465:        check_user_definable(idx, BOOLWRITE);
1.9       millert   466:        b1 = e1->tterm.Booleans[idx];
1.8       millert   467:        switch (compare) {
                    468:        case C_DIFFERENCE:
1.24    ! nicm      469:            b2 = next_entry->Booleans[idx];
        !           470:            if (!(no_boolean(b1) && no_boolean(b2)) && (b1 != b2))
1.9       millert   471:                (void) printf("\t%s: %s%s%s.\n",
1.11      millert   472:                              name,
                    473:                              dump_boolean(b1),
                    474:                              bool_sep,
                    475:                              dump_boolean(b2));
1.8       millert   476:            break;
                    477:
                    478:        case C_COMMON:
1.24    ! nicm      479:            if (b1 != ABSENT_BOOLEAN) {
        !           480:                found = TRUE;
        !           481:                for_each_entry() {
        !           482:                    b2 = next_entry->Booleans[idx];
        !           483:                    if (b1 != b2) {
        !           484:                        found = FALSE;
        !           485:                        break;
        !           486:                    }
        !           487:                }
        !           488:                if (found) {
        !           489:                    (void) printf("\t%s= %s.\n", name, dump_boolean(b1));
        !           490:                }
        !           491:            }
1.8       millert   492:            break;
                    493:
                    494:        case C_NAND:
1.24    ! nicm      495:            if (b1 == ABSENT_BOOLEAN) {
        !           496:                found = TRUE;
        !           497:                for_each_entry() {
        !           498:                    b2 = next_entry->Booleans[idx];
        !           499:                    if (b1 != b2) {
        !           500:                        found = FALSE;
        !           501:                        break;
        !           502:                    }
        !           503:                }
        !           504:                if (found) {
        !           505:                    (void) printf("\t!%s.\n", name);
        !           506:                }
        !           507:            }
1.8       millert   508:            break;
                    509:        }
                    510:        break;
1.1       millert   511:
1.9       millert   512:     case CMP_NUMBER:
1.24    ! nicm      513:        check_user_definable(idx, NUMWRITE);
1.9       millert   514:        n1 = e1->tterm.Numbers[idx];
1.8       millert   515:        switch (compare) {
                    516:        case C_DIFFERENCE:
1.24    ! nicm      517:            n2 = next_entry->Numbers[idx];
        !           518:            if (!(no_numeric(n1) && no_numeric(n2)) && n1 != n2) {
        !           519:                dump_numeric(n1, buf1);
        !           520:                dump_numeric(n2, buf2);
1.9       millert   521:                (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
1.24    ! nicm      522:            }
1.8       millert   523:            break;
1.1       millert   524:
1.8       millert   525:        case C_COMMON:
1.24    ! nicm      526:            if (n1 != ABSENT_NUMERIC) {
        !           527:                found = TRUE;
        !           528:                for_each_entry() {
        !           529:                    n2 = next_entry->Numbers[idx];
        !           530:                    if (n1 != n2) {
        !           531:                        found = FALSE;
        !           532:                        break;
        !           533:                    }
        !           534:                }
        !           535:                if (found) {
        !           536:                    dump_numeric(n1, buf1);
        !           537:                    (void) printf("\t%s= %s.\n", name, buf1);
        !           538:                }
        !           539:            }
1.8       millert   540:            break;
1.1       millert   541:
1.8       millert   542:        case C_NAND:
1.24    ! nicm      543:            if (n1 == ABSENT_NUMERIC) {
        !           544:                found = TRUE;
        !           545:                for_each_entry() {
        !           546:                    n2 = next_entry->Numbers[idx];
        !           547:                    if (n1 != n2) {
        !           548:                        found = FALSE;
        !           549:                        break;
        !           550:                    }
        !           551:                }
        !           552:                if (found) {
        !           553:                    (void) printf("\t!%s.\n", name);
        !           554:                }
        !           555:            }
1.8       millert   556:            break;
                    557:        }
                    558:        break;
1.1       millert   559:
1.9       millert   560:     case CMP_STRING:
1.24    ! nicm      561:        check_user_definable(idx, STRWRITE);
1.9       millert   562:        s1 = e1->tterm.Strings[idx];
1.8       millert   563:        switch (compare) {
                    564:        case C_DIFFERENCE:
1.24    ! nicm      565:            s2 = next_entry->Strings[idx];
        !           566:            if (!(no_string(s1) && no_string(s2)) && capcmp(idx, s1, s2)) {
        !           567:                dump_string(s1, buf1);
        !           568:                dump_string(s2, buf2);
1.8       millert   569:                if (strcmp(buf1, buf2))
1.9       millert   570:                    (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
1.8       millert   571:            }
                    572:            break;
1.1       millert   573:
1.8       millert   574:        case C_COMMON:
1.24    ! nicm      575:            if (s1 != ABSENT_STRING) {
        !           576:                found = TRUE;
        !           577:                for_each_entry() {
        !           578:                    s2 = next_entry->Strings[idx];
        !           579:                    if (capcmp(idx, s1, s2) != 0) {
        !           580:                        found = FALSE;
        !           581:                        break;
        !           582:                    }
        !           583:                }
        !           584:                if (found) {
        !           585:                    (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1));
        !           586:                }
        !           587:            }
1.8       millert   588:            break;
1.1       millert   589:
1.8       millert   590:        case C_NAND:
1.24    ! nicm      591:            if (s1 == ABSENT_STRING) {
        !           592:                found = TRUE;
        !           593:                for_each_entry() {
        !           594:                    s2 = next_entry->Strings[idx];
        !           595:                    if (s2 != s1) {
        !           596:                        found = FALSE;
        !           597:                        break;
        !           598:                    }
        !           599:                }
        !           600:                if (found) {
        !           601:                    (void) printf("\t!%s.\n", name);
        !           602:                }
        !           603:            }
1.8       millert   604:            break;
1.1       millert   605:        }
1.8       millert   606:        break;
1.9       millert   607:
                    608:     case CMP_USE:
                    609:        /* unlike the other modes, this compares *all* use entries */
                    610:        switch (compare) {
                    611:        case C_DIFFERENCE:
                    612:            if (!useeq(e1, e2)) {
                    613:                (void) fputs("\tuse: ", stdout);
                    614:                print_uses(e1, stdout);
                    615:                fputs(", ", stdout);
                    616:                print_uses(e2, stdout);
                    617:                fputs(".\n", stdout);
                    618:            }
                    619:            break;
                    620:
                    621:        case C_COMMON:
1.24    ! nicm      622:            if (e1->nuses) {
        !           623:                found = TRUE;
        !           624:                for_each_entry() {
        !           625:                    e2 = &entries[extra++];
        !           626:                    if (e2->nuses != e1->nuses || !useeq(e1, e2)) {
        !           627:                        found = FALSE;
        !           628:                        break;
        !           629:                    }
        !           630:                }
        !           631:                if (found) {
        !           632:                    (void) fputs("\tuse: ", stdout);
        !           633:                    print_uses(e1, stdout);
        !           634:                    fputs(".\n", stdout);
        !           635:                }
1.9       millert   636:            }
                    637:            break;
                    638:
                    639:        case C_NAND:
1.24    ! nicm      640:            if (!e1->nuses) {
        !           641:                found = TRUE;
        !           642:                for_each_entry() {
        !           643:                    e2 = &entries[extra++];
        !           644:                    if (e2->nuses != e1->nuses) {
        !           645:                        found = FALSE;
        !           646:                        break;
        !           647:                    }
        !           648:                }
        !           649:                if (found) {
        !           650:                    (void) printf("\t!use.\n");
        !           651:                }
        !           652:            }
1.9       millert   653:            break;
                    654:        }
1.8       millert   655:     }
1.1       millert   656: }
                    657:
                    658: /***************************************************************************
                    659:  *
                    660:  * Init string analysis
                    661:  *
                    662:  ***************************************************************************/
                    663:
1.24    ! nicm      664: #define DATA(from, to) { { from }, { to } }
        !           665: #define DATAX()        DATA("", "")
        !           666:
1.8       millert   667: typedef struct {
1.24    ! nicm      668:     const char from[4];
        !           669:     const char to[12];
1.8       millert   670: } assoc;
1.1       millert   671:
                    672: static const assoc std_caps[] =
                    673: {
                    674:     /* these are specified by X.364 and iBCS2 */
1.24    ! nicm      675:     DATA("\033c", "RIS"),      /* full reset */
        !           676:     DATA("\0337", "SC"),       /* save cursor */
        !           677:     DATA("\0338", "RC"),       /* restore cursor */
        !           678:     DATA("\033[r", "RSR"),     /* not an X.364 mnemonic */
        !           679:     DATA("\033[m", "SGR0"),    /* not an X.364 mnemonic */
        !           680:     DATA("\033[2J", "ED2"),    /* clear page */
1.1       millert   681:
                    682:     /* this group is specified by ISO 2022 */
1.24    ! nicm      683:     DATA("\033(0", "ISO DEC G0"),      /* enable DEC graphics for G0 */
        !           684:     DATA("\033(A", "ISO UK G0"),       /* enable UK chars for G0 */
        !           685:     DATA("\033(B", "ISO US G0"),       /* enable US chars for G0 */
        !           686:     DATA("\033)0", "ISO DEC G1"),      /* enable DEC graphics for G1 */
        !           687:     DATA("\033)A", "ISO UK G1"),       /* enable UK chars for G1 */
        !           688:     DATA("\033)B", "ISO US G1"),       /* enable US chars for G1 */
1.1       millert   689:
1.20      nicm      690:     /* these are DEC private controls widely supported by emulators */
1.24    ! nicm      691:     DATA("\033=", "DECPAM"),   /* application keypad mode */
        !           692:     DATA("\033>", "DECPNM"),   /* normal keypad mode */
        !           693:     DATA("\033<", "DECANSI"),  /* enter ANSI mode */
        !           694:     DATA("\033[!p", "DECSTR"), /* soft reset */
        !           695:     DATA("\033 F", "S7C1T"),   /* 7-bit controls */
1.1       millert   696:
1.24    ! nicm      697:     DATAX()
1.1       millert   698: };
                    699:
1.20      nicm      700: static const assoc std_modes[] =
                    701: /* ECMA \E[ ... [hl] modes recognized by many emulators */
                    702: {
1.24    ! nicm      703:     DATA("2", "AM"),           /* keyboard action mode */
        !           704:     DATA("4", "IRM"),          /* insert/replace mode */
        !           705:     DATA("12", "SRM"),         /* send/receive mode */
        !           706:     DATA("20", "LNM"),         /* linefeed mode */
        !           707:     DATAX()
1.20      nicm      708: };
                    709:
1.1       millert   710: static const assoc private_modes[] =
                    711: /* DEC \E[ ... [hl] modes recognized by many emulators */
                    712: {
1.24    ! nicm      713:     DATA("1", "CKM"),          /* application cursor keys */
        !           714:     DATA("2", "ANM"),          /* set VT52 mode */
        !           715:     DATA("3", "COLM"),         /* 132-column mode */
        !           716:     DATA("4", "SCLM"),         /* smooth scroll */
        !           717:     DATA("5", "SCNM"),         /* reverse video mode */
        !           718:     DATA("6", "OM"),           /* origin mode */
        !           719:     DATA("7", "AWM"),          /* wraparound mode */
        !           720:     DATA("8", "ARM"),          /* auto-repeat mode */
        !           721:     DATAX()
1.1       millert   722: };
                    723:
                    724: static const assoc ecma_highlights[] =
                    725: /* recognize ECMA attribute sequences */
                    726: {
1.24    ! nicm      727:     DATA("0", "NORMAL"),       /* normal */
        !           728:     DATA("1", "+BOLD"),                /* bold on */
        !           729:     DATA("2", "+DIM"),         /* dim on */
        !           730:     DATA("3", "+ITALIC"),      /* italic on */
        !           731:     DATA("4", "+UNDERLINE"),   /* underline on */
        !           732:     DATA("5", "+BLINK"),       /* blink on */
        !           733:     DATA("6", "+FASTBLINK"),   /* fastblink on */
        !           734:     DATA("7", "+REVERSE"),     /* reverse on */
        !           735:     DATA("8", "+INVISIBLE"),   /* invisible on */
        !           736:     DATA("9", "+DELETED"),     /* deleted on */
        !           737:     DATA("10", "MAIN-FONT"),   /* select primary font */
        !           738:     DATA("11", "ALT-FONT-1"),  /* select alternate font 1 */
        !           739:     DATA("12", "ALT-FONT-2"),  /* select alternate font 2 */
        !           740:     DATA("13", "ALT-FONT-3"),  /* select alternate font 3 */
        !           741:     DATA("14", "ALT-FONT-4"),  /* select alternate font 4 */
        !           742:     DATA("15", "ALT-FONT-5"),  /* select alternate font 5 */
        !           743:     DATA("16", "ALT-FONT-6"),  /* select alternate font 6 */
        !           744:     DATA("17", "ALT-FONT-7"),  /* select alternate font 7 */
        !           745:     DATA("18", "ALT-FONT-1"),  /* select alternate font 1 */
        !           746:     DATA("19", "ALT-FONT-1"),  /* select alternate font 1 */
        !           747:     DATA("20", "FRAKTUR"),     /* Fraktur font */
        !           748:     DATA("21", "DOUBLEUNDER"), /* double underline */
        !           749:     DATA("22", "-DIM"),                /* dim off */
        !           750:     DATA("23", "-ITALIC"),     /* italic off */
        !           751:     DATA("24", "-UNDERLINE"),  /* underline off */
        !           752:     DATA("25", "-BLINK"),      /* blink off */
        !           753:     DATA("26", "-FASTBLINK"),  /* fastblink off */
        !           754:     DATA("27", "-REVERSE"),    /* reverse off */
        !           755:     DATA("28", "-INVISIBLE"),  /* invisible off */
        !           756:     DATA("29", "-DELETED"),    /* deleted off */
        !           757:     DATAX()
1.1       millert   758: };
                    759:
1.24    ! nicm      760: #undef DATA
        !           761:
1.20      nicm      762: static int
                    763: skip_csi(const char *cap)
                    764: {
                    765:     int result = 0;
                    766:     if (cap[0] == '\033' && cap[1] == '[')
                    767:        result = 2;
                    768:     else if (UChar(cap[0]) == 0233)
                    769:        result = 1;
                    770:     return result;
                    771: }
                    772:
                    773: static bool
1.24    ! nicm      774: same_param(const char *table, const char *param, size_t length)
1.20      nicm      775: {
                    776:     bool result = FALSE;
                    777:     if (strncmp(table, param, length) == 0) {
                    778:        result = !isdigit(UChar(param[length]));
                    779:     }
                    780:     return result;
                    781: }
                    782:
                    783: static char *
1.24    ! nicm      784: lookup_params(const assoc * table, char *dst, char *src)
1.20      nicm      785: {
                    786:     char *result = 0;
                    787:     const char *ep = strtok(src, ";");
                    788:
                    789:     if (ep != 0) {
                    790:        const assoc *ap;
                    791:
                    792:        do {
                    793:            bool found = FALSE;
                    794:
1.24    ! nicm      795:            for (ap = table; ap->from[0]; ap++) {
1.20      nicm      796:                size_t tlen = strlen(ap->from);
                    797:
                    798:                if (same_param(ap->from, ep, tlen)) {
1.24    ! nicm      799:                    _nc_STRCAT(dst, ap->to, MAX_TERMINFO_LENGTH);
1.20      nicm      800:                    found = TRUE;
                    801:                    break;
                    802:                }
                    803:            }
                    804:
                    805:            if (!found)
1.24    ! nicm      806:                _nc_STRCAT(dst, ep, MAX_TERMINFO_LENGTH);
        !           807:            _nc_STRCAT(dst, ";", MAX_TERMINFO_LENGTH);
1.20      nicm      808:        } while
                    809:            ((ep = strtok((char *) 0, ";")));
                    810:
1.24    ! nicm      811:        dst[strlen(dst) - 1] = '\0';
1.20      nicm      812:
                    813:        result = dst;
                    814:     }
                    815:     return result;
                    816: }
                    817:
1.8       millert   818: static void
1.24    ! nicm      819: analyze_string(const char *name, const char *cap, TERMTYPE2 *tp)
1.1       millert   820: {
1.8       millert   821:     char buf2[MAX_TERMINFO_LENGTH];
1.20      nicm      822:     const char *sp;
1.8       millert   823:     const assoc *ap;
1.20      nicm      824:     int tp_lines = tp->Numbers[2];
1.1       millert   825:
1.24    ! nicm      826:     if (!VALID_STRING(cap))
1.1       millert   827:        return;
                    828:     (void) printf("%s: ", name);
                    829:
1.8       millert   830:     for (sp = cap; *sp; sp++) {
                    831:        int i;
1.20      nicm      832:        int csi;
1.8       millert   833:        size_t len = 0;
1.20      nicm      834:        size_t next;
1.1       millert   835:        const char *expansion = 0;
1.20      nicm      836:        char buf3[MAX_TERMINFO_LENGTH];
1.1       millert   837:
                    838:        /* first, check other capabilities in this entry */
1.8       millert   839:        for (i = 0; i < STRCOUNT; i++) {
                    840:            char *cp = tp->Strings[i];
1.1       millert   841:
1.24    ! nicm      842:            /* don't use function-key capabilities */
        !           843:            if (strnames[i] == NULL)
        !           844:                continue;
1.23      krw       845:            if (strnames[i][0] == 'k' && strnames[i][1] == 'f')
1.1       millert   846:                continue;
                    847:
1.24    ! nicm      848:            if (VALID_STRING(cp) &&
        !           849:                cp[0] != '\0' &&
        !           850:                cp != cap) {
1.1       millert   851:                len = strlen(cp);
1.24    ! nicm      852:                _nc_STRNCPY(buf2, sp, len);
1.1       millert   853:                buf2[len] = '\0';
                    854:
                    855:                if (_nc_capcmp(cp, buf2))
                    856:                    continue;
                    857:
1.24    ! nicm      858: #define ISRS(s)        (!strncmp((s), "is", (size_t) 2) || !strncmp((s), "rs", (size_t) 2))
1.1       millert   859:                /*
                    860:                 * Theoretically we just passed the test for translation
                    861:                 * (equality once the padding is stripped).  However, there
                    862:                 * are a few more hoops that need to be jumped so that
                    863:                 * identical pairs of initialization and reset strings
                    864:                 * don't just refer to each other.
                    865:                 */
                    866:                if (ISRS(name) || ISRS(strnames[i]))
                    867:                    if (cap < cp)
                    868:                        continue;
                    869: #undef ISRS
                    870:
                    871:                expansion = strnames[i];
                    872:                break;
                    873:            }
                    874:        }
                    875:
                    876:        /* now check the standard capabilities */
1.20      nicm      877:        if (!expansion) {
                    878:            csi = skip_csi(sp);
1.24    ! nicm      879:            for (ap = std_caps; ap->from[0]; ap++) {
1.20      nicm      880:                size_t adj = (size_t) (csi ? 2 : 0);
                    881:
1.1       millert   882:                len = strlen(ap->from);
1.20      nicm      883:                if (csi && skip_csi(ap->from) != csi)
                    884:                    continue;
                    885:                if (len > adj
                    886:                    && strncmp(ap->from + adj, sp + csi, len - adj) == 0) {
1.1       millert   887:                    expansion = ap->to;
1.20      nicm      888:                    len -= adj;
                    889:                    len += (size_t) csi;
1.1       millert   890:                    break;
                    891:                }
                    892:            }
1.20      nicm      893:        }
                    894:
                    895:        /* now check for standard-mode sequences */
                    896:        if (!expansion
                    897:            && (csi = skip_csi(sp)) != 0
1.24    ! nicm      898:            && (len = (strspn) (sp + csi, "0123456789;"))
1.20      nicm      899:            && (len < sizeof(buf3))
                    900:            && (next = (size_t) csi + len)
                    901:            && ((sp[next] == 'h') || (sp[next] == 'l'))) {
                    902:
1.24    ! nicm      903:            _nc_STRCPY(buf2,
        !           904:                       ((sp[next] == 'h')
        !           905:                        ? "ECMA+"
        !           906:                        : "ECMA-"),
        !           907:                       sizeof(buf2));
        !           908:            _nc_STRNCPY(buf3, sp + csi, len);
1.20      nicm      909:            buf3[len] = '\0';
                    910:
1.24    ! nicm      911:            expansion = lookup_params(std_modes, buf2, buf3);
1.20      nicm      912:        }
1.1       millert   913:
                    914:        /* now check for private-mode sequences */
                    915:        if (!expansion
1.20      nicm      916:            && (csi = skip_csi(sp)) != 0
                    917:            && sp[csi] == '?'
1.24    ! nicm      918:            && (len = (strspn) (sp + csi + 1, "0123456789;"))
1.20      nicm      919:            && (len < sizeof(buf3))
                    920:            && (next = (size_t) csi + 1 + len)
                    921:            && ((sp[next] == 'h') || (sp[next] == 'l'))) {
1.1       millert   922:
1.24    ! nicm      923:            _nc_STRCPY(buf2,
        !           924:                       ((sp[next] == 'h')
        !           925:                        ? "DEC+"
        !           926:                        : "DEC-"),
        !           927:                       sizeof(buf2));
        !           928:            _nc_STRNCPY(buf3, sp + csi + 1, len);
1.1       millert   929:            buf3[len] = '\0';
                    930:
1.24    ! nicm      931:            expansion = lookup_params(private_modes, buf2, buf3);
1.1       millert   932:        }
                    933:
                    934:        /* now check for ECMA highlight sequences */
                    935:        if (!expansion
1.20      nicm      936:            && (csi = skip_csi(sp)) != 0
1.24    ! nicm      937:            && (len = (strspn) (sp + csi, "0123456789;")) != 0
1.20      nicm      938:            && (len < sizeof(buf3))
                    939:            && (next = (size_t) csi + len)
                    940:            && sp[next] == 'm') {
1.1       millert   941:
1.24    ! nicm      942:            _nc_STRCPY(buf2, "SGR:", sizeof(buf2));
        !           943:            _nc_STRNCPY(buf3, sp + csi, len);
1.1       millert   944:            buf3[len] = '\0';
1.20      nicm      945:            len += (size_t) csi + 1;
1.1       millert   946:
1.24    ! nicm      947:            expansion = lookup_params(ecma_highlights, buf2, buf3);
1.20      nicm      948:        }
1.1       millert   949:
1.20      nicm      950:        if (!expansion
                    951:            && (csi = skip_csi(sp)) != 0
                    952:            && sp[csi] == 'm') {
                    953:            len = (size_t) csi + 1;
1.24    ! nicm      954:            _nc_STRCPY(buf2, "SGR:", sizeof(buf2));
        !           955:            _nc_STRCAT(buf2, ecma_highlights[0].to, sizeof(buf2));
1.1       millert   956:            expansion = buf2;
                    957:        }
1.20      nicm      958:
1.1       millert   959:        /* now check for scroll region reset */
1.20      nicm      960:        if (!expansion
                    961:            && (csi = skip_csi(sp)) != 0) {
                    962:            if (sp[csi] == 'r') {
1.1       millert   963:                expansion = "RSR";
1.20      nicm      964:                len = 1;
                    965:            } else {
1.24    ! nicm      966:                _nc_SPRINTF(buf2, _nc_SLIMIT(sizeof(buf2)) "1;%dr", tp_lines);
1.20      nicm      967:                len = strlen(buf2);
                    968:                if (strncmp(buf2, sp + csi, len) == 0)
                    969:                    expansion = "RSR";
                    970:            }
                    971:            len += (size_t) csi;
1.1       millert   972:        }
                    973:
                    974:        /* now check for home-down */
1.20      nicm      975:        if (!expansion
                    976:            && (csi = skip_csi(sp)) != 0) {
1.24    ! nicm      977:            _nc_SPRINTF(buf2, _nc_SLIMIT(sizeof(buf2)) "%d;1H", tp_lines);
1.1       millert   978:            len = strlen(buf2);
1.20      nicm      979:            if (strncmp(buf2, sp + csi, len) == 0) {
1.8       millert   980:                expansion = "LL";
1.20      nicm      981:            } else {
1.24    ! nicm      982:                _nc_SPRINTF(buf2, _nc_SLIMIT(sizeof(buf2)) "%dH", tp_lines);
1.20      nicm      983:                len = strlen(buf2);
                    984:                if (strncmp(buf2, sp + csi, len) == 0) {
                    985:                    expansion = "LL";
                    986:                }
                    987:            }
                    988:            len += (size_t) csi;
1.1       millert   989:        }
                    990:
                    991:        /* now look at the expansion we got, if any */
1.8       millert   992:        if (expansion) {
1.20      nicm      993:            printf("{%s}", expansion);
1.1       millert   994:            sp += len - 1;
1.8       millert   995:        } else {
1.1       millert   996:            /* couldn't match anything */
                    997:            buf2[0] = *sp;
                    998:            buf2[1] = '\0';
1.20      nicm      999:            fputs(TIC_EXPAND(buf2), stdout);
1.1       millert  1000:        }
                   1001:     }
1.20      nicm     1002:     putchar('\n');
1.1       millert  1003: }
                   1004:
                   1005: /***************************************************************************
                   1006:  *
                   1007:  * File comparison
                   1008:  *
                   1009:  ***************************************************************************/
                   1010:
1.8       millert  1011: static void
                   1012: file_comparison(int argc, char *argv[])
1.1       millert  1013: {
                   1014: #define MAXCOMPARE     2
                   1015:     /* someday we may allow comparisons on more files */
1.8       millert  1016:     int filecount = 0;
                   1017:     ENTRY *heads[MAXCOMPARE];
                   1018:     ENTRY *qp, *rp;
                   1019:     int i, n;
1.1       millert  1020:
1.20      nicm     1021:     memset(heads, 0, sizeof(heads));
1.24    ! nicm     1022:     dump_init((char *) 0, F_LITERAL, S_TERMINFO,
        !          1023:              FALSE, 0, 65535, itrace, FALSE, FALSE, FALSE);
1.1       millert  1024:
1.8       millert  1025:     for (n = 0; n < argc && n < MAXCOMPARE; n++) {
1.9       millert  1026:        if (freopen(argv[n], "r", stdin) == 0)
1.1       millert  1027:            _nc_err_abort("Can't open %s", argv[n]);
                   1028:
1.24    ! nicm     1029: #if NO_LEAKS
        !          1030:        entered[n].head = _nc_head;
        !          1031:        entered[n].tail = _nc_tail;
        !          1032: #endif
1.9       millert  1033:        _nc_head = _nc_tail = 0;
1.1       millert  1034:
                   1035:        /* parse entries out of the source file */
                   1036:        _nc_set_source(argv[n]);
1.20      nicm     1037:        _nc_read_entry_source(stdin, NULL, TRUE, literal, NULLHOOK);
1.1       millert  1038:
                   1039:        if (itrace)
1.8       millert  1040:            (void) fprintf(stderr, "Resolving file %d...\n", n - 0);
1.1       millert  1041:
1.9       millert  1042:        /* maybe do use resolution */
1.20      nicm     1043:        if (!_nc_resolve_uses2(!limited, literal)) {
1.1       millert  1044:            (void) fprintf(stderr,
1.11      millert  1045:                           "There are unresolved use entries in %s:\n",
                   1046:                           argv[n]);
1.9       millert  1047:            for_entry_list(qp) {
1.8       millert  1048:                if (qp->nuses) {
1.9       millert  1049:                    (void) fputs(qp->tterm.term_names, stderr);
                   1050:                    (void) fputc('\n', stderr);
                   1051:                }
1.8       millert  1052:            }
1.20      nicm     1053:            ExitProgram(EXIT_FAILURE);
1.1       millert  1054:        }
                   1055:
                   1056:        heads[filecount] = _nc_head;
                   1057:        filecount++;
                   1058:     }
                   1059:
                   1060:     /* OK, all entries are in core.  Ready to do the comparison */
                   1061:     if (itrace)
                   1062:        (void) fprintf(stderr, "Entries are now in core...\n");
                   1063:
1.9       millert  1064:     /* The entry-matching loop. Sigh, this is intrinsically quadratic. */
1.8       millert  1065:     for (qp = heads[0]; qp; qp = qp->next) {
1.1       millert  1066:        for (rp = heads[1]; rp; rp = rp->next)
1.8       millert  1067:            if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
1.9       millert  1068:                if (qp->ncrosslinks < MAX_CROSSLINKS)
                   1069:                    qp->crosslinks[qp->ncrosslinks] = rp;
                   1070:                qp->ncrosslinks++;
                   1071:
                   1072:                if (rp->ncrosslinks < MAX_CROSSLINKS)
                   1073:                    rp->crosslinks[rp->ncrosslinks] = qp;
                   1074:                rp->ncrosslinks++;
1.1       millert  1075:            }
                   1076:     }
                   1077:
                   1078:     /* now we have two circular lists with crosslinks */
                   1079:     if (itrace)
                   1080:        (void) fprintf(stderr, "Name matches are done...\n");
                   1081:
1.9       millert  1082:     for (qp = heads[0]; qp; qp = qp->next) {
                   1083:        if (qp->ncrosslinks > 1) {
1.1       millert  1084:            (void) fprintf(stderr,
1.11      millert  1085:                           "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
                   1086:                           _nc_first_name(qp->tterm.term_names),
                   1087:                           argv[0],
                   1088:                           qp->ncrosslinks,
                   1089:                           argv[1]);
1.9       millert  1090:            for (i = 0; i < qp->ncrosslinks; i++)
1.1       millert  1091:                (void) fprintf(stderr,
1.11      millert  1092:                               "\t%s\n",
                   1093:                               _nc_first_name((qp->crosslinks[i])->tterm.term_names));
1.1       millert  1094:        }
1.9       millert  1095:     }
                   1096:
                   1097:     for (rp = heads[1]; rp; rp = rp->next) {
                   1098:        if (rp->ncrosslinks > 1) {
1.1       millert  1099:            (void) fprintf(stderr,
1.11      millert  1100:                           "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
                   1101:                           _nc_first_name(rp->tterm.term_names),
                   1102:                           argv[1],
                   1103:                           rp->ncrosslinks,
                   1104:                           argv[0]);
1.9       millert  1105:            for (i = 0; i < rp->ncrosslinks; i++)
1.1       millert  1106:                (void) fprintf(stderr,
1.11      millert  1107:                               "\t%s\n",
                   1108:                               _nc_first_name((rp->crosslinks[i])->tterm.term_names));
1.1       millert  1109:        }
1.9       millert  1110:     }
1.1       millert  1111:
                   1112:     (void) printf("In file 1 (%s) only:\n", argv[0]);
                   1113:     for (qp = heads[0]; qp; qp = qp->next)
1.9       millert  1114:        if (qp->ncrosslinks == 0)
1.1       millert  1115:            (void) printf("\t%s\n",
1.11      millert  1116:                          _nc_first_name(qp->tterm.term_names));
1.1       millert  1117:
                   1118:     (void) printf("In file 2 (%s) only:\n", argv[1]);
                   1119:     for (rp = heads[1]; rp; rp = rp->next)
1.9       millert  1120:        if (rp->ncrosslinks == 0)
1.1       millert  1121:            (void) printf("\t%s\n",
1.11      millert  1122:                          _nc_first_name(rp->tterm.term_names));
1.1       millert  1123:
                   1124:     (void) printf("The following entries are equivalent:\n");
1.8       millert  1125:     for (qp = heads[0]; qp; qp = qp->next) {
1.9       millert  1126:        if (qp->ncrosslinks == 1) {
                   1127:            rp = qp->crosslinks[0];
1.1       millert  1128:
1.9       millert  1129:            repair_acsc(&qp->tterm);
                   1130:            repair_acsc(&rp->tterm);
                   1131: #if NCURSES_XNAMES
                   1132:            _nc_align_termtype(&qp->tterm, &rp->tterm);
                   1133: #endif
                   1134:            if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) {
                   1135:                char name1[NAMESIZE], name2[NAMESIZE];
1.1       millert  1136:
1.24    ! nicm     1137:                canonical_name(qp->tterm.term_names, name1);
        !          1138:                canonical_name(rp->tterm.term_names, name2);
1.1       millert  1139:
1.9       millert  1140:                (void) printf("%s = %s\n", name1, name2);
                   1141:            }
1.1       millert  1142:        }
                   1143:     }
                   1144:
                   1145:     (void) printf("Differing entries:\n");
                   1146:     termcount = 2;
1.8       millert  1147:     for (qp = heads[0]; qp; qp = qp->next) {
1.1       millert  1148:
1.9       millert  1149:        if (qp->ncrosslinks == 1) {
                   1150:            rp = qp->crosslinks[0];
1.2       millert  1151: #if NCURSES_XNAMES
1.9       millert  1152:            /* sorry - we have to do this on each pass */
1.2       millert  1153:            _nc_align_termtype(&qp->tterm, &rp->tterm);
                   1154: #endif
1.9       millert  1155:            if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) {
                   1156:                char name1[NAMESIZE], name2[NAMESIZE];
1.24    ! nicm     1157:                char *names[3];
        !          1158:
        !          1159:                names[0] = name1;
        !          1160:                names[1] = name2;
        !          1161:                names[2] = 0;
1.1       millert  1162:
1.9       millert  1163:                entries[0] = *qp;
                   1164:                entries[1] = *rp;
1.1       millert  1165:
1.24    ! nicm     1166:                canonical_name(qp->tterm.term_names, name1);
        !          1167:                canonical_name(rp->tterm.term_names, name2);
1.1       millert  1168:
1.9       millert  1169:                switch (compare) {
                   1170:                case C_DIFFERENCE:
1.24    ! nicm     1171:                    show_comparing(names);
1.9       millert  1172:                    compare_entry(compare_predicate, &entries->tterm, quiet);
                   1173:                    break;
1.1       millert  1174:
1.9       millert  1175:                case C_COMMON:
1.24    ! nicm     1176:                    show_comparing(names);
1.9       millert  1177:                    compare_entry(compare_predicate, &entries->tterm, quiet);
                   1178:                    break;
1.1       millert  1179:
1.9       millert  1180:                case C_NAND:
1.24    ! nicm     1181:                    show_comparing(names);
1.9       millert  1182:                    compare_entry(compare_predicate, &entries->tterm, quiet);
                   1183:                    break;
1.1       millert  1184:
1.9       millert  1185:                }
1.1       millert  1186:            }
                   1187:        }
                   1188:     }
                   1189: }
                   1190:
1.8       millert  1191: static void
                   1192: usage(void)
1.1       millert  1193: {
1.24    ! nicm     1194: #define DATA(s) s "\n"
        !          1195:     static const char head[] =
1.8       millert  1196:     {
1.24    ! nicm     1197:        DATA("Usage: infocmp [options] [-A directory] [-B directory] [termname...]")
        !          1198:        DATA("")
        !          1199:        DATA("Options:")
        !          1200:     };
        !          1201: #undef DATA
        !          1202:     /* length is given here so the compiler can make everything readonly */
        !          1203: #define DATA(s) s
        !          1204:     static const char options[][46] =
        !          1205:     {
        !          1206:        "  -0    print single-row"
1.8       millert  1207:        ,"  -1    print single-column"
                   1208:        ,"  -C    use termcap-names"
1.24    ! nicm     1209:        ,"  -D    print database locations"
        !          1210:        ,"  -E    format output as C tables"
1.8       millert  1211:        ,"  -F    compare terminfo-files"
1.24    ! nicm     1212:        ,"  -G    format %{number} to %'char'"
1.8       millert  1213:        ,"  -I    use terminfo-names"
1.24    ! nicm     1214:        ,"  -K    use termcap-names and BSD syntax"
1.8       millert  1215:        ,"  -L    use long names"
                   1216:        ,"  -R subset (see manpage)"
                   1217:        ,"  -T    eliminate size limits (test)"
1.24    ! nicm     1218:        ,"  -U    do not post-process entries"
1.8       millert  1219:        ,"  -V    print version"
1.24    ! nicm     1220:        ,"  -W    wrap long strings per -w[n]"
1.10      millert  1221: #if NCURSES_XNAMES
                   1222:        ,"  -a    with -F, list commented-out caps"
                   1223: #endif
1.8       millert  1224:        ,"  -c    list common capabilities"
                   1225:        ,"  -d    list different capabilities"
                   1226:        ,"  -e    format output for C initializer"
                   1227:        ,"  -f    with -1, format complex strings"
                   1228:        ,"  -g    format %'char' to %{number}"
                   1229:        ,"  -i    analyze initialization/reset"
                   1230:        ,"  -l    output terminfo names"
                   1231:        ,"  -n    list capabilities in neither"
                   1232:        ,"  -p    ignore padding specifiers"
1.24    ! nicm     1233:        ,"  -Q number  dump compiled description"
1.9       millert  1234:        ,"  -q    brief listing, removes headers"
1.8       millert  1235:        ,"  -r    with -C, output in termcap form"
1.9       millert  1236:        ,"  -r    with -F, resolve use-references"
1.8       millert  1237:        ,"  -s [d|i|l|c] sort fields"
1.20      nicm     1238: #if NCURSES_XNAMES
                   1239:        ,"  -t    suppress commented-out capabilities"
                   1240: #endif
1.8       millert  1241:        ,"  -u    produce source with 'use='"
                   1242:        ,"  -v number  (verbose)"
                   1243:        ,"  -w number  (width)"
1.20      nicm     1244: #if NCURSES_XNAMES
1.24    ! nicm     1245:        ,"  -x    unknown capabilities are user-defined"
1.20      nicm     1246: #endif
1.8       millert  1247:     };
1.24    ! nicm     1248: #undef DATA
        !          1249:     const size_t last = SIZEOF(options);
        !          1250:     const size_t left = (last + 1) / 2;
1.8       millert  1251:     size_t n;
                   1252:
1.24    ! nicm     1253:     fputs(head, stderr);
1.8       millert  1254:     for (n = 0; n < left; n++) {
1.24    ! nicm     1255:        size_t m = n + left;
1.8       millert  1256:        if (m < last)
1.24    ! nicm     1257:            fprintf(stderr, "%-40.40s%s\n", options[n], options[m]);
1.8       millert  1258:        else
1.24    ! nicm     1259:            fprintf(stderr, "%s\n", options[n]);
1.8       millert  1260:     }
1.20      nicm     1261:     ExitProgram(EXIT_FAILURE);
1.1       millert  1262: }
                   1263:
1.8       millert  1264: static char *
1.20      nicm     1265: any_initializer(const char *fmt, const char *type)
1.5       millert  1266: {
                   1267:     static char *initializer;
1.24    ! nicm     1268:     static size_t need;
1.5       millert  1269:     char *s;
                   1270:
1.16      deraadt  1271:     if (initializer == 0) {
1.24    ! nicm     1272:        need = (strlen(entries->tterm.term_names)
        !          1273:                + strlen(type)
        !          1274:                + strlen(fmt));
        !          1275:        initializer = (char *) malloc(need + 1);
        !          1276:        if (initializer == 0)
        !          1277:            failed("any_initializer");
1.16      deraadt  1278:     }
1.5       millert  1279:
1.24    ! nicm     1280:     _nc_STRCPY(initializer, entries->tterm.term_names, need);
1.8       millert  1281:     for (s = initializer; *s != 0 && *s != '|'; s++) {
1.20      nicm     1282:        if (!isalnum(UChar(*s)))
1.5       millert  1283:            *s = '_';
                   1284:     }
                   1285:     *s = 0;
1.24    ! nicm     1286:     _nc_SPRINTF(s, _nc_SLIMIT(need) fmt, type);
1.5       millert  1287:     return initializer;
                   1288: }
                   1289:
1.20      nicm     1290: static char *
                   1291: name_initializer(const char *type)
                   1292: {
                   1293:     return any_initializer("_%s_data", type);
                   1294: }
                   1295:
                   1296: static char *
                   1297: string_variable(const char *type)
                   1298: {
                   1299:     return any_initializer("_s_%s", type);
                   1300: }
                   1301:
1.5       millert  1302: /* dump C initializers for the terminal type */
1.8       millert  1303: static void
1.24    ! nicm     1304: dump_initializers(TERMTYPE2 *term)
1.5       millert  1305: {
1.20      nicm     1306:     unsigned n;
1.5       millert  1307:     const char *str = 0;
1.20      nicm     1308:
                   1309:     printf("\nstatic char %s[] = \"%s\";\n\n",
                   1310:           name_initializer("alias"), entries->tterm.term_names);
                   1311:
                   1312:     for_each_string(n, term) {
1.24    ! nicm     1313:        if (VALID_STRING(term->Strings[n])) {
        !          1314:            char buf[MAX_STRING], *sp, *tp;
1.20      nicm     1315:
                   1316:            tp = buf;
1.24    ! nicm     1317: #define TP_LIMIT       ((MAX_STRING - 5) - (size_t)(tp - buf))
1.20      nicm     1318:            *tp++ = '"';
                   1319:            for (sp = term->Strings[n];
1.24    ! nicm     1320:                 *sp != 0 && TP_LIMIT > 2;
1.20      nicm     1321:                 sp++) {
                   1322:                if (isascii(UChar(*sp))
                   1323:                    && isprint(UChar(*sp))
                   1324:                    && *sp != '\\'
                   1325:                    && *sp != '"')
                   1326:                    *tp++ = *sp;
                   1327:                else {
1.24    ! nicm     1328:                    _nc_SPRINTF(tp, _nc_SLIMIT(TP_LIMIT) "\\%03o", UChar(*sp));
        !          1329:                    tp += 4;
1.20      nicm     1330:                }
                   1331:            }
                   1332:            *tp++ = '"';
                   1333:            *tp = '\0';
                   1334:            (void) printf("static char %-20s[] = %s;\n",
1.24    ! nicm     1335:                          string_variable(ExtStrname(term, (int) n, strnames)),
        !          1336:                          buf);
1.20      nicm     1337:        }
                   1338:     }
                   1339:     printf("\n");
1.5       millert  1340:
1.6       millert  1341:     (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL);
1.5       millert  1342:
1.8       millert  1343:     for_each_boolean(n, term) {
                   1344:        switch ((int) (term->Booleans[n])) {
1.5       millert  1345:        case TRUE:
                   1346:            str = "TRUE";
                   1347:            break;
                   1348:
                   1349:        case FALSE:
                   1350:            str = "FALSE";
                   1351:            break;
                   1352:
                   1353:        case ABSENT_BOOLEAN:
                   1354:            str = "ABSENT_BOOLEAN";
                   1355:            break;
                   1356:
                   1357:        case CANCELLED_BOOLEAN:
                   1358:            str = "CANCELLED_BOOLEAN";
                   1359:            break;
                   1360:        }
1.20      nicm     1361:        (void) printf("\t/* %3u: %-8s */\t%s,\n",
1.24    ! nicm     1362:                      n, ExtBoolname(term, (int) n, boolnames), str);
1.5       millert  1363:     }
                   1364:     (void) printf("%s;\n", R_CURL);
                   1365:
                   1366:     (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL);
                   1367:
1.8       millert  1368:     for_each_number(n, term) {
                   1369:        char buf[BUFSIZ];
                   1370:        switch (term->Numbers[n]) {
1.5       millert  1371:        case ABSENT_NUMERIC:
                   1372:            str = "ABSENT_NUMERIC";
                   1373:            break;
                   1374:        case CANCELLED_NUMERIC:
                   1375:            str = "CANCELLED_NUMERIC";
                   1376:            break;
                   1377:        default:
1.24    ! nicm     1378:            _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) "%d", term->Numbers[n]);
1.5       millert  1379:            str = buf;
                   1380:            break;
                   1381:        }
1.20      nicm     1382:        (void) printf("\t/* %3u: %-8s */\t%s,\n", n,
1.24    ! nicm     1383:                      ExtNumname(term, (int) n, numnames), str);
1.5       millert  1384:     }
                   1385:     (void) printf("%s;\n", R_CURL);
                   1386:
                   1387:     (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL);
                   1388:
1.8       millert  1389:     for_each_string(n, term) {
1.5       millert  1390:
                   1391:        if (term->Strings[n] == ABSENT_STRING)
                   1392:            str = "ABSENT_STRING";
                   1393:        else if (term->Strings[n] == CANCELLED_STRING)
                   1394:            str = "CANCELLED_STRING";
1.8       millert  1395:        else {
1.24    ! nicm     1396:            str = string_variable(ExtStrname(term, (int) n, strnames));
1.5       millert  1397:        }
1.20      nicm     1398:        (void) printf("\t/* %3u: %-8s */\t%s,\n", n,
1.24    ! nicm     1399:                      ExtStrname(term, (int) n, strnames), str);
1.20      nicm     1400:     }
                   1401:     (void) printf("%s;\n", R_CURL);
                   1402:
1.5       millert  1403: #if NCURSES_XNAMES
1.20      nicm     1404:     if ((NUM_BOOLEANS(term) != BOOLCOUNT)
                   1405:        || (NUM_NUMBERS(term) != NUMCOUNT)
                   1406:        || (NUM_STRINGS(term) != STRCOUNT)) {
                   1407:        (void) printf("static char * %s[] = %s\n",
                   1408:                      name_initializer("string_ext"), L_CURL);
                   1409:        for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
                   1410:            (void) printf("\t/* %3u: bool */\t\"%s\",\n",
1.24    ! nicm     1411:                          n, ExtBoolname(term, (int) n, boolnames));
1.20      nicm     1412:        }
                   1413:        for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
                   1414:            (void) printf("\t/* %3u: num */\t\"%s\",\n",
1.24    ! nicm     1415:                          n, ExtNumname(term, (int) n, numnames));
1.20      nicm     1416:        }
                   1417:        for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
                   1418:            (void) printf("\t/* %3u: str */\t\"%s\",\n",
1.24    ! nicm     1419:                          n, ExtStrname(term, (int) n, strnames));
1.5       millert  1420:        }
1.20      nicm     1421:        (void) printf("%s;\n", R_CURL);
                   1422:     }
1.5       millert  1423: #endif
                   1424: }
                   1425:
                   1426: /* dump C initializers for the terminal type */
1.8       millert  1427: static void
1.24    ! nicm     1428: dump_termtype(TERMTYPE2 *term)
1.5       millert  1429: {
1.20      nicm     1430:     (void) printf("\t%s\n\t\t%s,\n", L_CURL, name_initializer("alias"));
1.5       millert  1431:     (void) printf("\t\t(char *)0,\t/* pointer to string table */\n");
                   1432:
                   1433:     (void) printf("\t\t%s,\n", name_initializer("bool"));
                   1434:     (void) printf("\t\t%s,\n", name_initializer("number"));
                   1435:
                   1436:     (void) printf("\t\t%s,\n", name_initializer("string"));
                   1437:
                   1438: #if NCURSES_XNAMES
                   1439:     (void) printf("#if NCURSES_XNAMES\n");
                   1440:     (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n");
                   1441:     (void) printf("\t\t%s,\t/* ...corresponding names */\n",
1.20      nicm     1442:                  ((NUM_BOOLEANS(term) != BOOLCOUNT)
                   1443:                   || (NUM_NUMBERS(term) != NUMCOUNT)
                   1444:                   || (NUM_STRINGS(term) != STRCOUNT))
1.11      millert  1445:                  ? name_initializer("string_ext")
                   1446:                  : "(char **)0");
1.5       millert  1447:
                   1448:     (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term));
1.8       millert  1449:     (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term));
                   1450:     (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term));
1.5       millert  1451:
1.8       millert  1452:     (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n",
1.11      millert  1453:                  NUM_BOOLEANS(term) - BOOLCOUNT);
1.8       millert  1454:     (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n",
1.11      millert  1455:                  NUM_NUMBERS(term) - NUMCOUNT);
1.8       millert  1456:     (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n",
1.11      millert  1457:                  NUM_STRINGS(term) - STRCOUNT);
1.5       millert  1458:
                   1459:     (void) printf("#endif /* NCURSES_XNAMES */\n");
1.20      nicm     1460: #else
                   1461:     (void) term;
1.5       millert  1462: #endif /* NCURSES_XNAMES */
                   1463:     (void) printf("\t%s\n", R_CURL);
                   1464: }
                   1465:
1.11      millert  1466: static int
                   1467: optarg_to_number(void)
                   1468: {
                   1469:     char *temp = 0;
                   1470:     long value = strtol(optarg, &temp, 0);
                   1471:
                   1472:     if (temp == 0 || temp == optarg || *temp != 0) {
                   1473:        fprintf(stderr, "Expected a number, not \"%s\"\n", optarg);
1.20      nicm     1474:        ExitProgram(EXIT_FAILURE);
                   1475:     }
                   1476:     return (int) value;
                   1477: }
                   1478:
                   1479: static char *
                   1480: terminal_env(void)
                   1481: {
                   1482:     char *terminal;
                   1483:
                   1484:     if ((terminal = getenv("TERM")) == 0) {
                   1485:        (void) fprintf(stderr,
                   1486:                       "%s: environment variable TERM not set\n",
                   1487:                       _nc_progname);
1.11      millert  1488:        exit(EXIT_FAILURE);
                   1489:     }
1.20      nicm     1490:     return terminal;
1.11      millert  1491: }
                   1492:
1.24    ! nicm     1493: /*
        !          1494:  * Show the databases that infocmp knows about.  The location to which it writes is
        !          1495:  */
        !          1496: static void
        !          1497: show_databases(void)
        !          1498: {
        !          1499:     DBDIRS state;
        !          1500:     int offset;
        !          1501:     const char *path2;
        !          1502:
        !          1503:     _nc_first_db(&state, &offset);
        !          1504:     while ((path2 = _nc_next_db(&state, &offset)) != 0) {
        !          1505:        printf("%s\n", path2);
        !          1506:     }
        !          1507:     _nc_last_db();
        !          1508: }
        !          1509:
1.1       millert  1510: /***************************************************************************
                   1511:  *
                   1512:  * Main sequence
                   1513:  *
                   1514:  ***************************************************************************/
                   1515:
1.24    ! nicm     1516: #if NO_LEAKS
        !          1517: #define MAIN_LEAKS() \
        !          1518:     _nc_free_termtype2(&entries[0].tterm); \
        !          1519:     _nc_free_termtype2(&entries[1].tterm); \
        !          1520:     free(myargv); \
        !          1521:     free(tfile); \
        !          1522:     free(tname)
        !          1523: #else
        !          1524: #define MAIN_LEAKS()           /* nothing */
        !          1525: #endif
        !          1526:
1.8       millert  1527: int
                   1528: main(int argc, char *argv[])
1.1       millert  1529: {
1.8       millert  1530:     /* Avoid "local data >32k" error with mwcc */
                   1531:     /* Also avoid overflowing smaller stacks on systems like AmigaOS */
1.20      nicm     1532:     path *tfile = 0;
                   1533:     char **tname = 0;
1.24    ! nicm     1534:     size_t maxterms;
1.20      nicm     1535:
                   1536:     char **myargv;
                   1537:
                   1538:     char *firstdir, *restdir;
1.24    ! nicm     1539:     int c;
1.8       millert  1540:     bool formatted = FALSE;
                   1541:     bool filecompare = FALSE;
                   1542:     int initdump = 0;
                   1543:     bool init_analyze = FALSE;
1.20      nicm     1544:     bool suppress_untranslatable = FALSE;
1.24    ! nicm     1545:     int quickdump = 0;
        !          1546:     bool wrap_strings = FALSE;
1.21      deraadt  1547:
1.22      deraadt  1548:     if (pledge("stdio rpath", NULL) == -1) {
1.24    ! nicm     1549:         perror("pledge");
        !          1550:         exit(1);
1.22      deraadt  1551:     }
1.1       millert  1552:
1.8       millert  1553:     /* where is the terminfo database location going to default to? */
                   1554:     restdir = firstdir = 0;
                   1555:
1.20      nicm     1556: #if NCURSES_XNAMES
                   1557:     use_extended_names(FALSE);
                   1558: #endif
1.24    ! nicm     1559:     _nc_strict_bsd = 0;
1.20      nicm     1560:
                   1561:     _nc_progname = _nc_rootname(argv[0]);
                   1562:
                   1563:     /* make sure we have enough space to add two terminal entries */
                   1564:     myargv = typeCalloc(char *, (size_t) (argc + 3));
1.24    ! nicm     1565:     if (myargv == 0)
        !          1566:        failed("myargv");
        !          1567:
1.20      nicm     1568:     memcpy(myargv, argv, (sizeof(char *) * (size_t) argc));
                   1569:     argv = myargv;
                   1570:
                   1571:     while ((c = getopt(argc,
                   1572:                       argv,
1.24    ! nicm     1573:                       "01A:aB:CcDdEeFfGgIiKLlnpQ:qR:rs:TtUuVv:Ww:x")) != -1) {
1.8       millert  1574:        switch (c) {
1.24    ! nicm     1575:        case '0':
        !          1576:            mwidth = 65535;
        !          1577:            mheight = 1;
        !          1578:            break;
        !          1579:
1.20      nicm     1580:        case '1':
                   1581:            mwidth = 0;
                   1582:            break;
                   1583:
                   1584:        case 'A':
                   1585:            firstdir = optarg;
                   1586:            break;
                   1587:
1.10      millert  1588: #if NCURSES_XNAMES
                   1589:        case 'a':
                   1590:            _nc_disable_period = TRUE;
                   1591:            use_extended_names(TRUE);
                   1592:            break;
                   1593: #endif
1.20      nicm     1594:        case 'B':
                   1595:            restdir = optarg;
                   1596:            break;
                   1597:
1.24    ! nicm     1598:        case 'K':
        !          1599:            _nc_strict_bsd = 1;
        !          1600:            /* FALLTHRU */
1.20      nicm     1601:        case 'C':
                   1602:            outform = F_TERMCAP;
                   1603:            tversion = "BSD";
                   1604:            if (sortmode == S_DEFAULT)
                   1605:                sortmode = S_TERMCAP;
                   1606:            break;
                   1607:
1.24    ! nicm     1608:        case 'D':
        !          1609:            show_databases();
        !          1610:            ExitProgram(EXIT_SUCCESS);
        !          1611:            break;
        !          1612:
1.20      nicm     1613:        case 'c':
                   1614:            compare = C_COMMON;
                   1615:            break;
                   1616:
1.8       millert  1617:        case 'd':
                   1618:            compare = C_DIFFERENCE;
                   1619:            break;
1.1       millert  1620:
1.8       millert  1621:        case 'E':
                   1622:            initdump |= 2;
                   1623:            break;
1.1       millert  1624:
1.20      nicm     1625:        case 'e':
                   1626:            initdump |= 1;
1.8       millert  1627:            break;
1.5       millert  1628:
1.20      nicm     1629:        case 'F':
                   1630:            filecompare = TRUE;
1.8       millert  1631:            break;
1.1       millert  1632:
1.8       millert  1633:        case 'f':
                   1634:            formatted = TRUE;
                   1635:            break;
1.1       millert  1636:
1.8       millert  1637:        case 'G':
                   1638:            numbers = 1;
                   1639:            break;
1.1       millert  1640:
1.8       millert  1641:        case 'g':
                   1642:            numbers = -1;
                   1643:            break;
1.1       millert  1644:
1.8       millert  1645:        case 'I':
                   1646:            outform = F_TERMINFO;
                   1647:            if (sortmode == S_DEFAULT)
                   1648:                sortmode = S_VARIABLE;
                   1649:            tversion = 0;
                   1650:            break;
1.1       millert  1651:
1.8       millert  1652:        case 'i':
                   1653:            init_analyze = TRUE;
                   1654:            break;
1.1       millert  1655:
1.8       millert  1656:        case 'L':
                   1657:            outform = F_VARIABLE;
                   1658:            if (sortmode == S_DEFAULT)
                   1659:                sortmode = S_VARIABLE;
                   1660:            break;
1.1       millert  1661:
1.20      nicm     1662:        case 'l':
                   1663:            outform = F_TERMINFO;
                   1664:            break;
                   1665:
1.8       millert  1666:        case 'n':
                   1667:            compare = C_NAND;
                   1668:            break;
1.1       millert  1669:
1.8       millert  1670:        case 'p':
                   1671:            ignorepads = TRUE;
                   1672:            break;
1.1       millert  1673:
1.24    ! nicm     1674:        case 'Q':
        !          1675:            quickdump = optarg_to_number();
        !          1676:            break;
        !          1677:
1.9       millert  1678:        case 'q':
                   1679:            quiet = TRUE;
                   1680:            s_absent = "-";
                   1681:            s_cancel = "@";
                   1682:            bool_sep = ", ";
                   1683:            break;
                   1684:
1.20      nicm     1685:        case 'R':
                   1686:            tversion = optarg;
                   1687:            break;
                   1688:
1.8       millert  1689:        case 'r':
                   1690:            tversion = 0;
                   1691:            break;
1.1       millert  1692:
1.8       millert  1693:        case 's':
                   1694:            if (*optarg == 'd')
                   1695:                sortmode = S_NOSORT;
                   1696:            else if (*optarg == 'i')
                   1697:                sortmode = S_TERMINFO;
                   1698:            else if (*optarg == 'l')
                   1699:                sortmode = S_VARIABLE;
                   1700:            else if (*optarg == 'c')
                   1701:                sortmode = S_TERMCAP;
                   1702:            else {
                   1703:                (void) fprintf(stderr,
1.20      nicm     1704:                               "%s: unknown sort mode\n",
                   1705:                               _nc_progname);
                   1706:                ExitProgram(EXIT_FAILURE);
1.8       millert  1707:            }
                   1708:            break;
1.1       millert  1709:
1.20      nicm     1710:        case 'T':
                   1711:            limited = FALSE;
                   1712:            break;
                   1713:
                   1714: #if NCURSES_XNAMES
                   1715:        case 't':
                   1716:            _nc_disable_period = FALSE;
                   1717:            suppress_untranslatable = TRUE;
                   1718:            break;
                   1719: #endif
                   1720:
                   1721:        case 'U':
                   1722:            literal = TRUE;
                   1723:            break;
                   1724:
1.8       millert  1725:        case 'u':
                   1726:            compare = C_USEALL;
                   1727:            break;
1.1       millert  1728:
1.20      nicm     1729:        case 'V':
                   1730:            puts(curses_version());
                   1731:            ExitProgram(EXIT_SUCCESS);
                   1732:
1.8       millert  1733:        case 'v':
1.24    ! nicm     1734:            itrace = (unsigned) optarg_to_number();
        !          1735:            use_verbosity(itrace);
        !          1736:            break;
        !          1737:
        !          1738:        case 'W':
        !          1739:            wrap_strings = TRUE;
1.8       millert  1740:            break;
1.1       millert  1741:
1.8       millert  1742:        case 'w':
1.11      millert  1743:            mwidth = optarg_to_number();
1.8       millert  1744:            break;
1.1       millert  1745:
1.20      nicm     1746: #if NCURSES_XNAMES
                   1747:        case 'x':
                   1748:            use_extended_names(TRUE);
1.8       millert  1749:            break;
1.20      nicm     1750: #endif
1.1       millert  1751:
1.8       millert  1752:        default:
                   1753:            usage();
                   1754:        }
1.20      nicm     1755:     }
                   1756:
1.24    ! nicm     1757:     maxterms = (size_t) (argc + 2 - optind);
        !          1758:     if ((tfile = typeMalloc(path, maxterms)) == 0)
        !          1759:        failed("tfile");
        !          1760:     if ((tname = typeCalloc(char *, maxterms)) == 0)
        !          1761:          failed("tname");
        !          1762:     if ((entries = typeCalloc(ENTRY, maxterms)) == 0)
        !          1763:        failed("entries");
        !          1764: #if NO_LEAKS
        !          1765:     if ((entered = typeCalloc(ENTERED, maxterms)) == 0)
        !          1766:        failed("entered");
        !          1767: #endif
1.20      nicm     1768:
                   1769:     if (tfile == 0
                   1770:        || tname == 0
                   1771:        || entries == 0) {
                   1772:        fprintf(stderr, "%s: not enough memory\n", _nc_progname);
                   1773:        ExitProgram(EXIT_FAILURE);
                   1774:     }
1.1       millert  1775:
1.8       millert  1776:     /* by default, sort by terminfo name */
                   1777:     if (sortmode == S_DEFAULT)
                   1778:        sortmode = S_TERMINFO;
1.1       millert  1779:
1.8       millert  1780:     /* make sure we have at least one terminal name to work with */
                   1781:     if (optind >= argc)
1.20      nicm     1782:        argv[argc++] = terminal_env();
1.1       millert  1783:
1.8       millert  1784:     /* if user is after a comparison, make sure we have two entries */
                   1785:     if (compare != C_DEFAULT && optind >= argc - 1)
1.20      nicm     1786:        argv[argc++] = terminal_env();
1.1       millert  1787:
1.24    ! nicm     1788:     /* exactly one terminal name with no options means display it */
1.8       millert  1789:     /* exactly two terminal names with no options means do -d */
1.24    ! nicm     1790:     if (compare == C_DEFAULT) {
        !          1791:        switch (argc - optind) {
        !          1792:        default:
        !          1793:            fprintf(stderr, "%s: too many names to compare\n", _nc_progname);
        !          1794:            ExitProgram(EXIT_FAILURE);
        !          1795:        case 1:
        !          1796:            break;
        !          1797:        case 2:
        !          1798:            compare = C_DIFFERENCE;
        !          1799:            break;
        !          1800:        }
        !          1801:     }
        !          1802:
        !          1803:     /* set up for display */
        !          1804:     dump_init(tversion, outform, sortmode,
        !          1805:              wrap_strings, mwidth, mheight, itrace,
        !          1806:              formatted, FALSE, quickdump);
1.1       millert  1807:
1.8       millert  1808:     if (!filecompare) {
                   1809:        /* grab the entries */
                   1810:        termcount = 0;
                   1811:        for (; optind < argc; optind++) {
1.20      nicm     1812:            const char *directory = termcount ? restdir : firstdir;
                   1813:            int status;
1.8       millert  1814:
1.20      nicm     1815:            tname[termcount] = argv[optind];
1.8       millert  1816:
1.20      nicm     1817:            if (directory) {
1.24    ! nicm     1818: #if NCURSES_USE_DATABASE
1.20      nicm     1819: #if MIXEDCASE_FILENAMES
                   1820: #define LEAF_FMT "%c"
                   1821: #else
                   1822: #define LEAF_FMT "%02x"
                   1823: #endif
1.24    ! nicm     1824:                _nc_SPRINTF(tfile[termcount],
        !          1825:                            _nc_SLIMIT(sizeof(path))
        !          1826:                            "%s/" LEAF_FMT "/%s",
        !          1827:                            directory,
        !          1828:                            UChar(*argv[optind]), argv[optind]);
1.20      nicm     1829:                if (itrace)
                   1830:                    (void) fprintf(stderr,
                   1831:                                   "%s: reading entry %s from file %s\n",
                   1832:                                   _nc_progname,
                   1833:                                   argv[optind], tfile[termcount]);
                   1834:
                   1835:                status = _nc_read_file_entry(tfile[termcount],
1.24    ! nicm     1836:                                             &entries[termcount].tterm);
1.20      nicm     1837: #else
                   1838:                (void) fprintf(stderr, "%s: terminfo files not supported\n",
                   1839:                               _nc_progname);
1.24    ! nicm     1840:                MAIN_LEAKS();
1.20      nicm     1841:                ExitProgram(EXIT_FAILURE);
                   1842: #endif
                   1843:            } else {
                   1844:                if (itrace)
                   1845:                    (void) fprintf(stderr,
                   1846:                                   "%s: reading entry %s from database\n",
                   1847:                                   _nc_progname,
                   1848:                                   tname[termcount]);
                   1849:
1.24    ! nicm     1850:                status = _nc_read_entry2(tname[termcount],
        !          1851:                                         tfile[termcount],
        !          1852:                                         &entries[termcount].tterm);
1.20      nicm     1853:            }
1.1       millert  1854:
1.20      nicm     1855:            if (status <= 0) {
                   1856:                (void) fprintf(stderr,
                   1857:                               "%s: couldn't open terminfo file %s.\n",
                   1858:                               _nc_progname,
                   1859:                               tfile[termcount]);
1.24    ! nicm     1860:                MAIN_LEAKS();
1.20      nicm     1861:                ExitProgram(EXIT_FAILURE);
1.1       millert  1862:            }
1.20      nicm     1863:            repair_acsc(&entries[termcount].tterm);
                   1864:            termcount++;
1.8       millert  1865:        }
1.1       millert  1866:
1.2       millert  1867: #if NCURSES_XNAMES
1.8       millert  1868:        if (termcount > 1)
1.9       millert  1869:            _nc_align_termtype(&entries[0].tterm, &entries[1].tterm);
1.2       millert  1870: #endif
                   1871:
1.8       millert  1872:        /* dump as C initializer for the terminal type */
                   1873:        if (initdump) {
                   1874:            if (initdump & 1)
1.9       millert  1875:                dump_termtype(&entries[0].tterm);
1.8       millert  1876:            if (initdump & 2)
1.9       millert  1877:                dump_initializers(&entries[0].tterm);
1.8       millert  1878:        }
1.1       millert  1879:
1.8       millert  1880:        /* analyze the init strings */
1.20      nicm     1881:        else if (init_analyze) {
1.1       millert  1882: #undef CUR
1.9       millert  1883: #define CUR    entries[0].tterm.
                   1884:            analyze_string("is1", init_1string, &entries[0].tterm);
                   1885:            analyze_string("is2", init_2string, &entries[0].tterm);
                   1886:            analyze_string("is3", init_3string, &entries[0].tterm);
                   1887:            analyze_string("rs1", reset_1string, &entries[0].tterm);
                   1888:            analyze_string("rs2", reset_2string, &entries[0].tterm);
                   1889:            analyze_string("rs3", reset_3string, &entries[0].tterm);
                   1890:            analyze_string("smcup", enter_ca_mode, &entries[0].tterm);
                   1891:            analyze_string("rmcup", exit_ca_mode, &entries[0].tterm);
1.24    ! nicm     1892:            analyze_string("smkx", keypad_xmit, &entries[0].tterm);
        !          1893:            analyze_string("rmkx", keypad_local, &entries[0].tterm);
1.1       millert  1894: #undef CUR
1.20      nicm     1895:        } else {
1.24    ! nicm     1896:            int i;
        !          1897:            int len;
1.1       millert  1898:
1.20      nicm     1899:            /*
                   1900:             * Here's where the real work gets done
                   1901:             */
                   1902:            switch (compare) {
                   1903:            case C_DEFAULT:
                   1904:                if (itrace)
                   1905:                    (void) fprintf(stderr,
                   1906:                                   "%s: about to dump %s\n",
                   1907:                                   _nc_progname,
                   1908:                                   tname[0]);
1.24    ! nicm     1909:                if (!quiet)
        !          1910:                    (void)
        !          1911:                        printf("#\tReconstructed via infocmp from file: %s\n",
        !          1912:                               tfile[0]);
1.20      nicm     1913:                dump_entry(&entries[0].tterm,
                   1914:                           suppress_untranslatable,
                   1915:                           limited,
                   1916:                           numbers,
                   1917:                           NULL);
                   1918:                len = show_entry();
                   1919:                if (itrace)
                   1920:                    (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
                   1921:                break;
1.1       millert  1922:
1.20      nicm     1923:            case C_DIFFERENCE:
1.24    ! nicm     1924:                show_comparing(tname);
1.20      nicm     1925:                compare_entry(compare_predicate, &entries->tterm, quiet);
                   1926:                break;
1.1       millert  1927:
1.20      nicm     1928:            case C_COMMON:
1.24    ! nicm     1929:                show_comparing(tname);
1.20      nicm     1930:                compare_entry(compare_predicate, &entries->tterm, quiet);
                   1931:                break;
1.1       millert  1932:
1.20      nicm     1933:            case C_NAND:
1.24    ! nicm     1934:                show_comparing(tname);
1.20      nicm     1935:                compare_entry(compare_predicate, &entries->tterm, quiet);
                   1936:                break;
1.1       millert  1937:
1.20      nicm     1938:            case C_USEALL:
                   1939:                if (itrace)
                   1940:                    (void) fprintf(stderr, "%s: dumping use entry\n", _nc_progname);
                   1941:                dump_entry(&entries[0].tterm,
                   1942:                           suppress_untranslatable,
                   1943:                           limited,
                   1944:                           numbers,
                   1945:                           use_predicate);
                   1946:                for (i = 1; i < termcount; i++)
                   1947:                    dump_uses(tname[i], !(outform == F_TERMCAP
                   1948:                                          || outform == F_TCONVERR));
                   1949:                len = show_entry();
                   1950:                if (itrace)
                   1951:                    (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
                   1952:                break;
                   1953:            }
1.1       millert  1954:        }
1.24    ! nicm     1955:     } else if (compare == C_USEALL) {
1.8       millert  1956:        (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
1.24    ! nicm     1957:     } else if (compare == C_DEFAULT) {
1.8       millert  1958:        (void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
1.24    ! nicm     1959:     } else if (argc - optind != 2) {
1.8       millert  1960:        (void) fprintf(stderr,
1.11      millert  1961:                       "File comparison needs exactly two file arguments.\n");
1.24    ! nicm     1962:     } else {
1.8       millert  1963:        file_comparison(argc - optind, argv + optind);
1.24    ! nicm     1964:     }
1.1       millert  1965:
1.24    ! nicm     1966:     MAIN_LEAKS();
1.8       millert  1967:     ExitProgram(EXIT_SUCCESS);
1.1       millert  1968: }
                   1969:
                   1970: /* infocmp.c ends here */