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

1.8     ! millert     1: /*     $OpenBSD: infocmp.c,v 1.7 1999/12/06 02:14:34 millert Exp $     */
1.1       millert     2:
                      3: /****************************************************************************
1.8     ! millert     4:  * Copyright (c) 1998-2000 Free Software Foundation, Inc.                   *
1.1       millert     5:  *                                                                          *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a  *
                      7:  * copy of this software and associated documentation files (the            *
                      8:  * "Software"), to deal in the Software without restriction, including      *
                      9:  * without limitation the rights to use, copy, modify, merge, publish,      *
                     10:  * distribute, distribute with modifications, sublicense, and/or sell       *
                     11:  * copies of the Software, and to permit persons to whom the Software is    *
                     12:  * furnished to do so, subject to the following conditions:                 *
                     13:  *                                                                          *
                     14:  * The above copyright notice and this permission notice shall be included  *
                     15:  * in all copies or substantial portions of the Software.                   *
                     16:  *                                                                          *
                     17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
                     18:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
                     19:  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
                     20:  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
                     21:  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
                     22:  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
                     23:  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
                     24:  *                                                                          *
                     25:  * Except as contained in this notice, the name(s) of the above copyright   *
                     26:  * holders shall not be used in advertising or otherwise to promote the     *
                     27:  * sale, use or other dealings in this Software without prior written       *
                     28:  * authorization.                                                           *
                     29:  ****************************************************************************/
                     30:
                     31: /****************************************************************************
                     32:  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
                     33:  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
                     34:  ****************************************************************************/
                     35:
                     36: /*
                     37:  *     infocmp.c -- decompile an entry, or compare two entries
                     38:  *             written by Eric S. Raymond
                     39:  */
                     40:
                     41: #include <progs.priv.h>
                     42:
                     43: #include <term_entry.h>
                     44: #include <dump_entry.h>
                     45:
1.8     ! millert    46: MODULE_ID("$From: infocmp.c,v 1.48 2000/01/15 22:46:12 tom Exp $")
1.1       millert    47:
                     48: #define L_CURL "{"
                     49: #define R_CURL "}"
                     50:
                     51: #define MAXTERMS       32      /* max # terminal arguments we can handle */
                     52:
                     53: const char *_nc_progname = "infocmp";
                     54:
1.8     ! millert    55: typedef char path[PATH_MAX];
1.1       millert    56:
                     57: /***************************************************************************
                     58:  *
                     59:  * The following control variables, together with the contents of the
                     60:  * terminfo entries, completely determine the actions of the program.
                     61:  *
                     62:  ***************************************************************************/
                     63:
                     64: static char *tname[MAXTERMS];  /* terminal type names */
                     65: static TERMTYPE term[MAXTERMS];        /* terminfo entries */
                     66: static int termcount;          /* count of terminal entries */
                     67:
                     68: static const char *tversion;   /* terminfo version selected */
1.3       millert    69: static int numbers = 0;                /* format "%'char'" to/from "%{number}" */
1.8     ! millert    70: static int outform = F_TERMINFO;       /* output format */
1.1       millert    71: static int sortmode;           /* sort_mode */
                     72: static int itrace;             /* trace flag for debugging */
                     73: static int mwidth = 60;
                     74:
                     75: /* main comparison mode */
                     76: static int compare;
                     77: #define C_DEFAULT      0       /* don't force comparison mode */
                     78: #define C_DIFFERENCE   1       /* list differences between two terminals */
                     79: #define C_COMMON       2       /* list common capabilities */
                     80: #define C_NAND         3       /* list capabilities in neither terminal */
                     81: #define C_USEALL       4       /* generate relative use-form entry */
                     82: static bool ignorepads;                /* ignore pad prefixes when diffing */
                     83:
                     84: #if NO_LEAKS
                     85: #undef ExitProgram
1.8     ! millert    86: static void
        !            87: ExitProgram(int code) GCC_NORETURN;
        !            88: /* prototype is to get gcc to accept the noreturn attribute */
        !            89: static void
        !            90: ExitProgram(int code)
1.1       millert    91: {
1.8     ! millert    92:     while (termcount-- > 0)
        !            93:        _nc_free_termtype(&term[termcount]);
        !            94:     _nc_leaks_dump_entry();
        !            95:     _nc_free_and_exit(code);
1.1       millert    96: }
                     97: #endif
                     98:
1.8     ! millert    99: static char *
        !           100: canonical_name(char *ptr, char *buf)
1.1       millert   101: /* extract the terminal type's primary name */
                    102: {
1.8     ! millert   103:     char *bp;
1.1       millert   104:
                    105:     (void) strcpy(buf, ptr);
1.8     ! millert   106:     if ((bp = strchr(buf, '|')) != (char *) NULL)
1.1       millert   107:        *bp = '\0';
                    108:
1.8     ! millert   109:     return (buf);
1.1       millert   110: }
                    111:
                    112: /***************************************************************************
                    113:  *
                    114:  * Predicates for dump function
                    115:  *
                    116:  ***************************************************************************/
                    117:
1.8     ! millert   118: static int
        !           119: capcmp(const char *s, const char *t)
1.1       millert   120: /* capability comparison function */
                    121: {
                    122:     if (!VALID_STRING(s) && !VALID_STRING(t))
1.8     ! millert   123:        return (0);
1.1       millert   124:     else if (!VALID_STRING(s) || !VALID_STRING(t))
1.8     ! millert   125:        return (1);
1.1       millert   126:
                    127:     if (ignorepads)
1.8     ! millert   128:        return (_nc_capcmp(s, t));
1.1       millert   129:     else
1.8     ! millert   130:        return (strcmp(s, t));
1.1       millert   131: }
                    132:
1.8     ! millert   133: static int
        !           134: use_predicate(int type, int idx)
1.1       millert   135: /* predicate function to use for use decompilation */
                    136: {
1.8     ! millert   137:     TERMTYPE *tp;
1.1       millert   138:
1.8     ! millert   139:     switch (type) {
        !           140:     case BOOLEAN:{
        !           141:            int is_set = FALSE;
1.1       millert   142:
1.8     ! millert   143:            /*
        !           144:             * This assumes that multiple use entries are supposed
        !           145:             * to contribute the logical or of their boolean capabilities.
        !           146:             * This is true if we take the semantics of multiple uses to
        !           147:             * be 'each capability gets the first non-default value found
        !           148:             * in the sequence of use entries'.
        !           149:             */
        !           150:            for (tp = &term[1]; tp < term + termcount; tp++)
        !           151:                if (tp->Booleans[idx]) {
        !           152:                    is_set = TRUE;
        !           153:                    break;
1.1       millert   154:                }
1.8     ! millert   155:            if (is_set != term->Booleans[idx])
        !           156:                return (!is_set);
        !           157:            else
        !           158:                return (FAIL);
        !           159:        }
1.1       millert   160:
1.8     ! millert   161:     case NUMBER:{
        !           162:            int value = ABSENT_NUMERIC;
1.1       millert   163:
1.8     ! millert   164:            /*
        !           165:             * We take the semantics of multiple uses to be 'each
        !           166:             * capability gets the first non-default value found
        !           167:             * in the sequence of use entries'.
        !           168:             */
        !           169:            for (tp = &term[1]; tp < term + termcount; tp++)
        !           170:                if (tp->Numbers[idx] >= 0) {
        !           171:                    value = tp->Numbers[idx];
        !           172:                    break;
1.1       millert   173:                }
                    174:
1.8     ! millert   175:            if (value != term->Numbers[idx])
        !           176:                return (value != ABSENT_NUMERIC);
        !           177:            else
        !           178:                return (FAIL);
        !           179:        }
        !           180:
        !           181:     case STRING:{
        !           182:            char *termstr, *usestr = ABSENT_STRING;
1.1       millert   183:
1.8     ! millert   184:            termstr = term->Strings[idx];
1.1       millert   185:
1.8     ! millert   186:            /*
        !           187:             * We take the semantics of multiple uses to be 'each
        !           188:             * capability gets the first non-default value found
        !           189:             * in the sequence of use entries'.
        !           190:             */
        !           191:            for (tp = &term[1]; tp < term + termcount; tp++)
        !           192:                if (tp->Strings[idx]) {
        !           193:                    usestr = tp->Strings[idx];
        !           194:                    break;
        !           195:                }
        !           196:
        !           197:            if (usestr == ABSENT_STRING && termstr == ABSENT_STRING)
        !           198:                return (FAIL);
        !           199:            else if (!usestr || !termstr || capcmp(usestr, termstr))
        !           200:                return (TRUE);
        !           201:            else
        !           202:                return (FAIL);
1.1       millert   203:        }
1.8     ! millert   204:     }
1.1       millert   205:
1.8     ! millert   206:     return (FALSE);            /* pacify compiler */
1.1       millert   207: }
                    208:
1.8     ! millert   209: static bool
        !           210: entryeq(TERMTYPE * t1, TERMTYPE * t2)
1.1       millert   211: /* are two terminal types equal */
                    212: {
1.8     ! millert   213:     int i;
1.1       millert   214:
1.2       millert   215:     for (i = 0; i < NUM_BOOLEANS(t1); i++)
1.1       millert   216:        if (t1->Booleans[i] != t2->Booleans[i])
1.8     ! millert   217:            return (FALSE);
1.1       millert   218:
1.2       millert   219:     for (i = 0; i < NUM_NUMBERS(t1); i++)
1.1       millert   220:        if (t1->Numbers[i] != t2->Numbers[i])
1.8     ! millert   221:            return (FALSE);
1.1       millert   222:
1.2       millert   223:     for (i = 0; i < NUM_STRINGS(t1); i++)
1.1       millert   224:        if (capcmp(t1->Strings[i], t2->Strings[i]))
1.8     ! millert   225:            return (FALSE);
1.1       millert   226:
1.8     ! millert   227:     return (TRUE);
1.1       millert   228: }
                    229:
                    230: #define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers)
                    231:
1.8     ! millert   232: static void
        !           233: compare_predicate(int type, int idx, const char *name)
1.1       millert   234: /* predicate function to use for entry difference reports */
                    235: {
1.8     ! millert   236:     register TERMTYPE *t1 = &term[0];
        !           237:     register TERMTYPE *t2 = &term[1];
        !           238:     char *s1, *s2;
        !           239:
        !           240:     switch (type) {
        !           241:     case BOOLEAN:
        !           242:        switch (compare) {
        !           243:        case C_DIFFERENCE:
        !           244:            if (t1->Booleans[idx] != t2->Booleans[idx])
        !           245:                (void) printf("\t%s: %c:%c.\n",
        !           246:                    name,
        !           247:                    t1->Booleans[idx] ? 'T' : 'F',
        !           248:                    t2->Booleans[idx] ? 'T' : 'F');
        !           249:            break;
        !           250:
        !           251:        case C_COMMON:
        !           252:            if (t1->Booleans[idx] && t2->Booleans[idx])
        !           253:                (void) printf("\t%s= T.\n", name);
        !           254:            break;
        !           255:
        !           256:        case C_NAND:
        !           257:            if (!t1->Booleans[idx] && !t2->Booleans[idx])
        !           258:                (void) printf("\t!%s.\n", name);
        !           259:            break;
        !           260:        }
        !           261:        break;
1.1       millert   262:
1.8     ! millert   263:     case NUMBER:
        !           264:        switch (compare) {
        !           265:        case C_DIFFERENCE:
        !           266:            if (t1->Numbers[idx] != t2->Numbers[idx])
        !           267:                (void) printf("\t%s: %d:%d.\n",
        !           268:                    name, t1->Numbers[idx], t2->Numbers[idx]);
        !           269:            break;
1.1       millert   270:
1.8     ! millert   271:        case C_COMMON:
        !           272:            if (t1->Numbers[idx] != -1 && t2->Numbers[idx] != -1
        !           273:                && t1->Numbers[idx] == t2->Numbers[idx])
        !           274:                (void) printf("\t%s= %d.\n", name, t1->Numbers[idx]);
        !           275:            break;
1.1       millert   276:
1.8     ! millert   277:        case C_NAND:
        !           278:            if (t1->Numbers[idx] == -1 && t2->Numbers[idx] == -1)
        !           279:                (void) printf("\t!%s.\n", name);
        !           280:            break;
        !           281:        }
        !           282:        break;
1.1       millert   283:
1.8     ! millert   284:     case STRING:
        !           285:        s1 = t1->Strings[idx];
        !           286:        s2 = t2->Strings[idx];
        !           287:        switch (compare) {
        !           288:        case C_DIFFERENCE:
        !           289:            if (capcmp(s1, s2)) {
        !           290:                char buf1[BUFSIZ], buf2[BUFSIZ];
        !           291:
        !           292:                if (s1 == (char *) NULL)
        !           293:                    (void) strcpy(buf1, "NULL");
        !           294:                else {
        !           295:                    (void) strcpy(buf1, "'");
        !           296:                    (void) strcat(buf1, TIC_EXPAND(s1));
        !           297:                    (void) strcat(buf1, "'");
        !           298:                }
1.1       millert   299:
1.8     ! millert   300:                if (s2 == (char *) NULL)
        !           301:                    (void) strcpy(buf2, "NULL");
        !           302:                else {
        !           303:                    (void) strcpy(buf2, "'");
        !           304:                    (void) strcat(buf2, TIC_EXPAND(s2));
        !           305:                    (void) strcat(buf2, "'");
1.1       millert   306:                }
                    307:
1.8     ! millert   308:                if (strcmp(buf1, buf2))
        !           309:                    (void) printf("\t%s: %s, %s.\n",
        !           310:                        name, buf1, buf2);
        !           311:            }
        !           312:            break;
1.1       millert   313:
1.8     ! millert   314:        case C_COMMON:
        !           315:            if (s1 && s2 && !capcmp(s1, s2))
        !           316:                (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1));
        !           317:            break;
1.1       millert   318:
1.8     ! millert   319:        case C_NAND:
        !           320:            if (!s1 && !s2)
        !           321:                (void) printf("\t!%s.\n", name);
        !           322:            break;
1.1       millert   323:        }
1.8     ! millert   324:        break;
        !           325:     }
1.1       millert   326:
                    327: }
                    328:
                    329: /***************************************************************************
                    330:  *
                    331:  * Init string analysis
                    332:  *
                    333:  ***************************************************************************/
                    334:
1.8     ! millert   335: typedef struct {
        !           336:     const char *from;
        !           337:     const char *to;
        !           338: } assoc;
1.1       millert   339:
                    340: static const assoc std_caps[] =
                    341: {
                    342:     /* these are specified by X.364 and iBCS2 */
1.8     ! millert   343:     {"\033c", "RIS"},          /* full reset */
        !           344:     {"\0337", "SC"},           /* save cursor */
        !           345:     {"\0338", "RC"},           /* restore cursor */
        !           346:     {"\033[r", "RSR"},         /* not an X.364 mnemonic */
        !           347:     {"\033[m", "SGR0"},                /* not an X.364 mnemonic */
        !           348:     {"\033[2J", "ED2"},                /* clear page */
1.1       millert   349:
                    350:     /* this group is specified by ISO 2022 */
1.8     ! millert   351:     {"\033(0", "ISO DEC G0"},  /* enable DEC graphics for G0 */
        !           352:     {"\033(A", "ISO UK G0"},   /* enable UK chars for G0 */
        !           353:     {"\033(B", "ISO US G0"},   /* enable US chars for G0 */
        !           354:     {"\033)0", "ISO DEC G1"},  /* enable DEC graphics for G1 */
        !           355:     {"\033)A", "ISO UK G1"},   /* enable UK chars for G1 */
        !           356:     {"\033)B", "ISO US G1"},   /* enable US chars for G1 */
1.1       millert   357:
                    358:     /* these are DEC private modes widely supported by emulators */
1.8     ! millert   359:     {"\033=", "DECPAM"},       /* application keypad mode */
        !           360:     {"\033>", "DECPNM"},       /* normal keypad mode */
        !           361:     {"\033<", "DECANSI"},      /* enter ANSI mode */
1.1       millert   362:
1.8     ! millert   363:     {(char *) 0, (char *) 0}
1.1       millert   364: };
                    365:
                    366: static const assoc private_modes[] =
                    367: /* DEC \E[ ... [hl] modes recognized by many emulators */
                    368: {
1.8     ! millert   369:     {"1", "CKM"},              /* application cursor keys */
        !           370:     {"2", "ANM"},              /* set VT52 mode */
        !           371:     {"3", "COLM"},             /* 132-column mode */
        !           372:     {"4", "SCLM"},             /* smooth scroll */
        !           373:     {"5", "SCNM"},             /* reverse video mode */
        !           374:     {"6", "OM"},               /* origin mode */
        !           375:     {"7", "AWM"},              /* wraparound mode */
        !           376:     {"8", "ARM"},              /* auto-repeat mode */
        !           377:     {(char *) 0, (char *) 0}
1.1       millert   378: };
                    379:
                    380: static const assoc ecma_highlights[] =
                    381: /* recognize ECMA attribute sequences */
                    382: {
1.8     ! millert   383:     {"0", "NORMAL"},           /* normal */
        !           384:     {"1", "+BOLD"},            /* bold on */
        !           385:     {"2", "+DIM"},             /* dim on */
        !           386:     {"3", "+ITALIC"},          /* italic on */
        !           387:     {"4", "+UNDERLINE"},       /* underline on */
        !           388:     {"5", "+BLINK"},           /* blink on */
        !           389:     {"6", "+FASTBLINK"},       /* fastblink on */
        !           390:     {"7", "+REVERSE"},         /* reverse on */
        !           391:     {"8", "+INVISIBLE"},       /* invisible on */
        !           392:     {"9", "+DELETED"},         /* deleted on */
        !           393:     {"10", "MAIN-FONT"},       /* select primary font */
        !           394:     {"11", "ALT-FONT-1"},      /* select alternate font 1 */
        !           395:     {"12", "ALT-FONT-2"},      /* select alternate font 2 */
        !           396:     {"13", "ALT-FONT-3"},      /* select alternate font 3 */
        !           397:     {"14", "ALT-FONT-4"},      /* select alternate font 4 */
        !           398:     {"15", "ALT-FONT-5"},      /* select alternate font 5 */
        !           399:     {"16", "ALT-FONT-6"},      /* select alternate font 6 */
        !           400:     {"17", "ALT-FONT-7"},      /* select alternate font 7 */
        !           401:     {"18", "ALT-FONT-1"},      /* select alternate font 1 */
        !           402:     {"19", "ALT-FONT-1"},      /* select alternate font 1 */
        !           403:     {"20", "FRAKTUR"},         /* Fraktur font */
        !           404:     {"21", "DOUBLEUNDER"},     /* double underline */
        !           405:     {"22", "-DIM"},            /* dim off */
        !           406:     {"23", "-ITALIC"},         /* italic off */
        !           407:     {"24", "-UNDERLINE"},      /* underline off */
        !           408:     {"25", "-BLINK"},          /* blink off */
        !           409:     {"26", "-FASTBLINK"},      /* fastblink off */
        !           410:     {"27", "-REVERSE"},                /* reverse off */
        !           411:     {"28", "-INVISIBLE"},      /* invisible off */
        !           412:     {"29", "-DELETED"},                /* deleted off */
        !           413:     {(char *) 0, (char *) 0}
1.1       millert   414: };
                    415:
1.8     ! millert   416: static void
        !           417: analyze_string(const char *name, const char *cap, TERMTYPE * tp)
1.1       millert   418: {
1.8     ! millert   419:     char buf[MAX_TERMINFO_LENGTH];
        !           420:     char buf2[MAX_TERMINFO_LENGTH];
        !           421:     const char *sp, *ep;
        !           422:     const assoc *ap;
1.1       millert   423:
                    424:     if (cap == ABSENT_STRING || cap == CANCELLED_STRING)
                    425:        return;
                    426:     (void) printf("%s: ", name);
                    427:
                    428:     buf[0] = '\0';
1.8     ! millert   429:     for (sp = cap; *sp; sp++) {
        !           430:        int i;
        !           431:        size_t len = 0;
1.1       millert   432:        const char *expansion = 0;
                    433:
                    434:        /* first, check other capabilities in this entry */
1.8     ! millert   435:        for (i = 0; i < STRCOUNT; i++) {
        !           436:            char *cp = tp->Strings[i];
1.1       millert   437:
                    438:            /* don't use soft-key capabilities */
                    439:            if (strnames[i][0] == 'k' && strnames[i][0] == 'f')
                    440:                continue;
                    441:
1.8     ! millert   442:            if (cp != ABSENT_STRING && cp != CANCELLED_STRING && cp[0] && cp
        !           443:                != cap) {
1.1       millert   444:                len = strlen(cp);
                    445:                (void) strncpy(buf2, sp, len);
                    446:                buf2[len] = '\0';
                    447:
                    448:                if (_nc_capcmp(cp, buf2))
                    449:                    continue;
                    450:
                    451: #define ISRS(s)        (!strncmp((s), "is", 2) || !strncmp((s), "rs", 2))
                    452:                /*
                    453:                 * Theoretically we just passed the test for translation
                    454:                 * (equality once the padding is stripped).  However, there
                    455:                 * are a few more hoops that need to be jumped so that
                    456:                 * identical pairs of initialization and reset strings
                    457:                 * don't just refer to each other.
                    458:                 */
                    459:                if (ISRS(name) || ISRS(strnames[i]))
                    460:                    if (cap < cp)
                    461:                        continue;
                    462: #undef ISRS
                    463:
                    464:                expansion = strnames[i];
                    465:                break;
                    466:            }
                    467:        }
                    468:
                    469:        /* now check the standard capabilities */
                    470:        if (!expansion)
1.8     ! millert   471:            for (ap = std_caps; ap->from; ap++) {
1.1       millert   472:                len = strlen(ap->from);
                    473:
1.8     ! millert   474:                if (strncmp(ap->from, sp, len) == 0) {
1.1       millert   475:                    expansion = ap->to;
                    476:                    break;
                    477:                }
                    478:            }
                    479:
                    480:        /* now check for private-mode sequences */
                    481:        if (!expansion
1.8     ! millert   482:            && sp[0] == '\033' && sp[1] == '[' && sp[2] == '?'
        !           483:            && (len = strspn(sp + 3, "0123456789;"))
        !           484:            && ((sp[3 + len] == 'h') || (sp[3 + len] == 'l'))) {
        !           485:            char buf3[MAX_TERMINFO_LENGTH];
1.1       millert   486:
                    487:            (void) strcpy(buf2, (sp[3 + len] == 'h') ? "DEC+" : "DEC-");
                    488:            (void) strncpy(buf3, sp + 3, len);
                    489:            len += 4;
                    490:            buf3[len] = '\0';
                    491:
                    492:            ep = strtok(buf3, ";");
                    493:            do {
1.8     ! millert   494:                bool found = FALSE;
        !           495:
        !           496:                for (ap = private_modes; ap->from; ap++) {
        !           497:                    size_t tlen = strlen(ap->from);
1.1       millert   498:
1.8     ! millert   499:                    if (strncmp(ap->from, ep, tlen) == 0) {
        !           500:                        (void) strcat(buf2, ap->to);
        !           501:                        found = TRUE;
        !           502:                        break;
        !           503:                    }
        !           504:                }
        !           505:
        !           506:                if (!found)
        !           507:                    (void) strcat(buf2, ep);
        !           508:                (void) strcat(buf2, ";");
        !           509:            } while
        !           510:                ((ep = strtok((char *) NULL, ";")));
1.1       millert   511:            buf2[strlen(buf2) - 1] = '\0';
                    512:            expansion = buf2;
                    513:        }
                    514:
                    515:        /* now check for ECMA highlight sequences */
                    516:        if (!expansion
1.8     ! millert   517:            && sp[0] == '\033' && sp[1] == '['
        !           518:            && (len = strspn(sp + 2, "0123456789;"))
        !           519:            && sp[2 + len] == 'm') {
        !           520:            char buf3[MAX_TERMINFO_LENGTH];
1.1       millert   521:
                    522:            (void) strcpy(buf2, "SGR:");
                    523:            (void) strncpy(buf3, sp + 2, len);
                    524:            len += 3;
                    525:            buf3[len] = '\0';
                    526:
                    527:            ep = strtok(buf3, ";");
                    528:            do {
1.8     ! millert   529:                bool found = FALSE;
        !           530:
        !           531:                for (ap = ecma_highlights; ap->from; ap++) {
        !           532:                    size_t tlen = strlen(ap->from);
        !           533:
        !           534:                    if (strncmp(ap->from, ep, tlen) == 0) {
        !           535:                        (void) strcat(buf2, ap->to);
        !           536:                        found = TRUE;
        !           537:                        break;
        !           538:                    }
        !           539:                }
1.1       millert   540:
1.8     ! millert   541:                if (!found)
        !           542:                    (void) strcat(buf2, ep);
        !           543:                (void) strcat(buf2, ";");
        !           544:            } while
        !           545:                ((ep = strtok((char *) NULL, ";")));
1.1       millert   546:
                    547:            buf2[strlen(buf2) - 1] = '\0';
                    548:            expansion = buf2;
                    549:        }
                    550:        /* now check for scroll region reset */
1.8     ! millert   551:        if (!expansion) {
1.1       millert   552:            (void) sprintf(buf2, "\033[1;%dr", tp->Numbers[2]);
                    553:            len = strlen(buf2);
                    554:            if (strncmp(buf2, sp, len) == 0)
                    555:                expansion = "RSR";
                    556:        }
                    557:
                    558:        /* now check for home-down */
1.8     ! millert   559:        if (!expansion) {
1.1       millert   560:            (void) sprintf(buf2, "\033[%d;1H", tp->Numbers[2]);
                    561:            len = strlen(buf2);
                    562:            if (strncmp(buf2, sp, len) == 0)
1.8     ! millert   563:                expansion = "LL";
1.1       millert   564:        }
                    565:
                    566:        /* now look at the expansion we got, if any */
1.8     ! millert   567:        if (expansion) {
1.1       millert   568:            (void) sprintf(buf + strlen(buf), "{%s}", expansion);
                    569:            sp += len - 1;
                    570:            continue;
1.8     ! millert   571:        } else {
1.1       millert   572:            /* couldn't match anything */
                    573:            buf2[0] = *sp;
                    574:            buf2[1] = '\0';
                    575:            (void) strcat(buf, TIC_EXPAND(buf2));
                    576:        }
                    577:     }
                    578:     (void) printf("%s\n", buf);
                    579: }
                    580:
                    581: /***************************************************************************
                    582:  *
                    583:  * File comparison
                    584:  *
                    585:  ***************************************************************************/
                    586:
1.8     ! millert   587: static void
        !           588: file_comparison(int argc, char *argv[])
1.1       millert   589: {
                    590: #define MAXCOMPARE     2
                    591:     /* someday we may allow comparisons on more files */
1.8     ! millert   592:     int filecount = 0;
        !           593:     ENTRY *heads[MAXCOMPARE];
        !           594:     ENTRY *tails[MAXCOMPARE];
        !           595:     ENTRY *qp, *rp;
        !           596:     int i, n;
1.1       millert   597:
1.8     ! millert   598:     dump_init((char *) NULL, F_LITERAL, S_TERMINFO, 0, itrace, FALSE);
1.1       millert   599:
1.8     ! millert   600:     for (n = 0; n < argc && n < MAXCOMPARE; n++) {
1.1       millert   601:        if (freopen(argv[n], "r", stdin) == NULL)
                    602:            _nc_err_abort("Can't open %s", argv[n]);
                    603:
1.8     ! millert   604:        _nc_head = _nc_tail = (ENTRY *) NULL;
1.1       millert   605:
                    606:        /* parse entries out of the source file */
                    607:        _nc_set_source(argv[n]);
                    608:        _nc_read_entry_source(stdin, NULL, TRUE, FALSE, NULLHOOK);
                    609:
                    610:        if (itrace)
1.8     ! millert   611:            (void) fprintf(stderr, "Resolving file %d...\n", n - 0);
1.1       millert   612:
                    613:        /* do use resolution */
1.8     ! millert   614:        if (!_nc_resolve_uses()) {
1.1       millert   615:            (void) fprintf(stderr,
1.8     ! millert   616:                "There are unresolved use entries in %s:\n",
        !           617:                argv[n]);
1.1       millert   618:            for_entry_list(qp)
1.8     ! millert   619:                if (qp->nuses) {
        !           620:                (void) fputs(qp->tterm.term_names, stderr);
        !           621:                (void) fputc('\n', stderr);
        !           622:            }
1.1       millert   623:            exit(EXIT_FAILURE);
                    624:        }
                    625:
                    626:        heads[filecount] = _nc_head;
                    627:        tails[filecount] = _nc_tail;
                    628:        filecount++;
                    629:     }
                    630:
                    631:     /* OK, all entries are in core.  Ready to do the comparison */
                    632:     if (itrace)
                    633:        (void) fprintf(stderr, "Entries are now in core...\n");
                    634:
                    635:     /*
                    636:      * The entry-matching loop.  We're not using the use[]
                    637:      * slots any more (they got zeroed out by resolve_uses) so
                    638:      * we stash each entry's matches in the other file there.
                    639:      * Sigh, this is intrinsically quadratic.
                    640:      */
1.8     ! millert   641:     for (qp = heads[0]; qp; qp = qp->next) {
1.1       millert   642:        for (rp = heads[1]; rp; rp = rp->next)
1.8     ! millert   643:            if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
1.1       millert   644:                /*
                    645:                 * This is why the uses structure parent element is
                    646:                 * (void *) -- so we can have either (char *) for
                    647:                 * names or entry structure pointers in them and still
                    648:                 * be type-safe.
                    649:                 */
                    650:                if (qp->nuses < MAX_USES)
1.8     ! millert   651:                    qp->uses[qp->nuses].parent = (void *) rp;
1.1       millert   652:                qp->nuses++;
                    653:
                    654:                if (rp->nuses < MAX_USES)
1.8     ! millert   655:                    rp->uses[rp->nuses].parent = (void *) qp;
1.1       millert   656:                rp->nuses++;
                    657:            }
                    658:     }
                    659:
                    660:     /* now we have two circular lists with crosslinks */
                    661:     if (itrace)
                    662:        (void) fprintf(stderr, "Name matches are done...\n");
                    663:
                    664:     for (qp = heads[0]; qp; qp = qp->next)
1.8     ! millert   665:        if (qp->nuses > 1) {
1.1       millert   666:            (void) fprintf(stderr,
1.8     ! millert   667:                "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
        !           668:                _nc_first_name(qp->tterm.term_names),
        !           669:                argv[0],
        !           670:                qp->nuses,
        !           671:                argv[1]);
1.1       millert   672:            for (i = 0; i < qp->nuses; i++)
                    673:                (void) fprintf(stderr,
1.8     ! millert   674:                    "\t%s\n",
        !           675:                    _nc_first_name(((ENTRY *) qp->uses[i].parent)->tterm.term_names));
1.1       millert   676:        }
                    677:     for (rp = heads[1]; rp; rp = rp->next)
1.8     ! millert   678:        if (rp->nuses > 1) {
1.1       millert   679:            (void) fprintf(stderr,
1.8     ! millert   680:                "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
        !           681:                _nc_first_name(rp->tterm.term_names),
        !           682:                argv[1],
        !           683:                rp->nuses,
        !           684:                argv[0]);
1.1       millert   685:            for (i = 0; i < rp->nuses; i++)
                    686:                (void) fprintf(stderr,
1.8     ! millert   687:                    "\t%s\n",
        !           688:                    _nc_first_name(((ENTRY *) rp->uses[i].parent)->tterm.term_names));
1.1       millert   689:        }
                    690:
                    691:     (void) printf("In file 1 (%s) only:\n", argv[0]);
                    692:     for (qp = heads[0]; qp; qp = qp->next)
                    693:        if (qp->nuses == 0)
                    694:            (void) printf("\t%s\n",
1.8     ! millert   695:                _nc_first_name(qp->tterm.term_names));
1.1       millert   696:
                    697:     (void) printf("In file 2 (%s) only:\n", argv[1]);
                    698:     for (rp = heads[1]; rp; rp = rp->next)
                    699:        if (rp->nuses == 0)
                    700:            (void) printf("\t%s\n",
1.8     ! millert   701:                _nc_first_name(rp->tterm.term_names));
1.1       millert   702:
                    703:     (void) printf("The following entries are equivalent:\n");
1.8     ! millert   704:     for (qp = heads[0]; qp; qp = qp->next) {
        !           705:        rp = (ENTRY *) qp->uses[0].parent;
1.1       millert   706:
1.8     ! millert   707:        if (qp->nuses == 1 && entryeq(&qp->tterm, &rp->tterm)) {
1.1       millert   708:            char name1[NAMESIZE], name2[NAMESIZE];
                    709:
                    710:            (void) canonical_name(qp->tterm.term_names, name1);
                    711:            (void) canonical_name(rp->tterm.term_names, name2);
                    712:
                    713:            (void) printf("%s = %s\n", name1, name2);
                    714:        }
                    715:     }
                    716:
                    717:     (void) printf("Differing entries:\n");
                    718:     termcount = 2;
1.8     ! millert   719:     for (qp = heads[0]; qp; qp = qp->next) {
        !           720:        rp = (ENTRY *) qp->uses[0].parent;
1.1       millert   721:
1.2       millert   722: #if NCURSES_XNAMES
                    723:        if (termcount > 1)
                    724:            _nc_align_termtype(&qp->tterm, &rp->tterm);
                    725: #endif
1.8     ! millert   726:        if (qp->nuses == 1 && !entryeq(&qp->tterm, &rp->tterm)) {
1.1       millert   727:            char name1[NAMESIZE], name2[NAMESIZE];
                    728:
1.2       millert   729:            term[0] = qp->tterm;
                    730:            term[1] = rp->tterm;
1.1       millert   731:
                    732:            (void) canonical_name(qp->tterm.term_names, name1);
                    733:            (void) canonical_name(rp->tterm.term_names, name2);
                    734:
1.8     ! millert   735:            switch (compare) {
1.1       millert   736:            case C_DIFFERENCE:
                    737:                if (itrace)
1.8     ! millert   738:                    (void) fprintf(stderr, "infocmp: dumping differences\n");
1.1       millert   739:                (void) printf("comparing %s to %s.\n", name1, name2);
1.2       millert   740:                compare_entry(compare_predicate, term);
1.1       millert   741:                break;
                    742:
                    743:            case C_COMMON:
                    744:                if (itrace)
                    745:                    (void) fprintf(stderr,
1.8     ! millert   746:                        "infocmp: dumping common capabilities\n");
1.1       millert   747:                (void) printf("comparing %s to %s.\n", name1, name2);
1.2       millert   748:                compare_entry(compare_predicate, term);
1.1       millert   749:                break;
                    750:
                    751:            case C_NAND:
                    752:                if (itrace)
                    753:                    (void) fprintf(stderr,
1.8     ! millert   754:                        "infocmp: dumping differences\n");
1.1       millert   755:                (void) printf("comparing %s to %s.\n", name1, name2);
1.2       millert   756:                compare_entry(compare_predicate, term);
1.1       millert   757:                break;
                    758:
                    759:            }
                    760:        }
                    761:     }
                    762: }
                    763:
1.8     ! millert   764: static void
        !           765: usage(void)
1.1       millert   766: {
1.8     ! millert   767:     static const char *tbl[] =
        !           768:     {
        !           769:        "Usage: infocmp [options] [-A directory] [-B directory] [termname...]"
        !           770:        ,""
        !           771:        ,"Options:"
        !           772:        ,"  -1    print single-column"
        !           773:        ,"  -C    use termcap-names"
        !           774:        ,"  -F    compare terminfo-files"
        !           775:        ,"  -I    use terminfo-names"
        !           776:        ,"  -L    use long names"
        !           777:        ,"  -R subset (see manpage)"
        !           778:        ,"  -T    eliminate size limits (test)"
        !           779:        ,"  -V    print version"
        !           780:        ,"  -c    list common capabilities"
        !           781:        ,"  -d    list different capabilities"
        !           782:        ,"  -e    format output for C initializer"
        !           783:        ,"  -E    format output as C tables"
        !           784:        ,"  -f    with -1, format complex strings"
        !           785:        ,"  -G    format %{number} to %'char'"
        !           786:        ,"  -g    format %'char' to %{number}"
        !           787:        ,"  -i    analyze initialization/reset"
        !           788:        ,"  -l    output terminfo names"
        !           789:        ,"  -n    list capabilities in neither"
        !           790:        ,"  -p    ignore padding specifiers"
        !           791:        ,"  -r    with -C, output in termcap form"
        !           792:        ,"  -s [d|i|l|c] sort fields"
        !           793:        ,"  -u    produce source with 'use='"
        !           794:        ,"  -v number  (verbose)"
        !           795:        ,"  -w number  (width)"
        !           796:     };
        !           797:     const size_t first = 3;
        !           798:     const size_t last = sizeof(tbl) / sizeof(tbl[0]);
        !           799:     const size_t left = (last - first + 1) / 2 + first;
        !           800:     size_t n;
        !           801:
        !           802:     for (n = 0; n < left; n++) {
        !           803:        size_t m = (n < first) ? last : n + left - first;
        !           804:        if (m < last)
        !           805:            fprintf(stderr, "%-40.40s%s\n", tbl[n], tbl[m]);
        !           806:        else
        !           807:            fprintf(stderr, "%s\n", tbl[n]);
        !           808:     }
        !           809:     exit(EXIT_FAILURE);
1.1       millert   810: }
                    811:
1.8     ! millert   812: static char *
        !           813: name_initializer(const char *type)
1.5       millert   814: {
                    815:     static char *initializer;
                    816:     char *s;
                    817:
                    818:     if (initializer == 0)
                    819:        initializer = malloc(strlen(term->term_names) + 20);
                    820:
                    821:     (void) sprintf(initializer, "%s_data_%s", type, term->term_names);
1.8     ! millert   822:     for (s = initializer; *s != 0 && *s != '|'; s++) {
1.5       millert   823:        if (!isalnum(*s))
                    824:            *s = '_';
                    825:     }
                    826:     *s = 0;
                    827:     return initializer;
                    828: }
                    829:
                    830: /* dump C initializers for the terminal type */
1.8     ! millert   831: static void
        !           832: dump_initializers(void)
1.5       millert   833: {
1.8     ! millert   834:     int n;
1.5       millert   835:     const char *str = 0;
1.8     ! millert   836:     int size;
1.5       millert   837:
1.6       millert   838:     (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL);
1.5       millert   839:
1.8     ! millert   840:     for_each_boolean(n, term) {
        !           841:        switch ((int) (term->Booleans[n])) {
1.5       millert   842:        case TRUE:
                    843:            str = "TRUE";
                    844:            break;
                    845:
                    846:        case FALSE:
                    847:            str = "FALSE";
                    848:            break;
                    849:
                    850:        case ABSENT_BOOLEAN:
                    851:            str = "ABSENT_BOOLEAN";
                    852:            break;
                    853:
                    854:        case CANCELLED_BOOLEAN:
                    855:            str = "CANCELLED_BOOLEAN";
                    856:            break;
                    857:        }
                    858:        (void) printf("\t/* %3d: %-8s */\t%s,\n",
1.8     ! millert   859:            n, ExtBoolname(term, n, boolnames), str);
1.5       millert   860:     }
                    861:     (void) printf("%s;\n", R_CURL);
                    862:
                    863:     (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL);
                    864:
1.8     ! millert   865:     for_each_number(n, term) {
        !           866:        char buf[BUFSIZ];
        !           867:        switch (term->Numbers[n]) {
1.5       millert   868:        case ABSENT_NUMERIC:
                    869:            str = "ABSENT_NUMERIC";
                    870:            break;
                    871:        case CANCELLED_NUMERIC:
                    872:            str = "CANCELLED_NUMERIC";
                    873:            break;
                    874:        default:
                    875:            sprintf(buf, "%d", term->Numbers[n]);
                    876:            str = buf;
                    877:            break;
                    878:        }
1.8     ! millert   879:        (void) printf("\t/* %3d: %-8s */\t%s,\n", n, ExtNumname(term, n,
        !           880:                numnames), str);
1.5       millert   881:     }
                    882:     (void) printf("%s;\n", R_CURL);
                    883:
                    884:     size = sizeof(TERMTYPE)
                    885:        + (NUM_BOOLEANS(term) * sizeof(term->Booleans[0]))
                    886:        + (NUM_NUMBERS(term) * sizeof(term->Numbers[0]));
                    887:
                    888:     (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL);
                    889:
1.8     ! millert   890:     for_each_string(n, term) {
        !           891:        char buf[BUFSIZ], *sp, *tp;
1.5       millert   892:
                    893:        if (term->Strings[n] == ABSENT_STRING)
                    894:            str = "ABSENT_STRING";
                    895:        else if (term->Strings[n] == CANCELLED_STRING)
                    896:            str = "CANCELLED_STRING";
1.8     ! millert   897:        else {
1.5       millert   898:            tp = buf;
                    899:            *tp++ = '"';
1.8     ! millert   900:            for (sp = term->Strings[n]; *sp; sp++) {
        !           901:                if (isascii(*sp) && isprint(*sp) && *sp != '\\' && *sp != '"')
1.5       millert   902:                    *tp++ = *sp;
1.8     ! millert   903:                else {
1.5       millert   904:                    (void) sprintf(tp, "\\%03o", *sp & 0xff);
                    905:                    tp += 4;
                    906:                }
                    907:            }
                    908:            *tp++ = '"';
                    909:            *tp = '\0';
                    910:            size += (strlen(term->Strings[n]) + 1);
                    911:            str = buf;
                    912:        }
                    913: #if NCURSES_XNAMES
1.8     ! millert   914:        if (n == STRCOUNT) {
1.5       millert   915:            (void) printf("%s;\n", R_CURL);
                    916:
1.8     ! millert   917:            (void) printf("static char * %s[] = %s\n",
        !           918:                name_initializer("string_ext"), L_CURL);
1.5       millert   919:        }
                    920: #endif
1.8     ! millert   921:        (void) printf("\t/* %3d: %-8s */\t%s,\n", n, ExtStrname(term, n,
        !           922:                strnames), str);
1.5       millert   923:     }
                    924:     (void) printf("%s;\n", R_CURL);
                    925: }
                    926:
                    927: /* dump C initializers for the terminal type */
1.8     ! millert   928: static void
        !           929: dump_termtype(void)
1.5       millert   930: {
                    931:     (void) printf("\t%s\n\t\t\"%s\",\n", L_CURL, term->term_names);
                    932:     (void) printf("\t\t(char *)0,\t/* pointer to string table */\n");
                    933:
                    934:     (void) printf("\t\t%s,\n", name_initializer("bool"));
                    935:     (void) printf("\t\t%s,\n", name_initializer("number"));
                    936:
                    937:     (void) printf("\t\t%s,\n", name_initializer("string"));
                    938:
                    939: #if NCURSES_XNAMES
                    940:     (void) printf("#if NCURSES_XNAMES\n");
                    941:     (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n");
                    942:     (void) printf("\t\t%s,\t/* ...corresponding names */\n",
                    943:        (NUM_STRINGS(term) != STRCOUNT)
1.8     ! millert   944:        ? name_initializer("string_ext")
        !           945:        : "(char **)0");
1.5       millert   946:
                    947:     (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term));
1.8     ! millert   948:     (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term));
        !           949:     (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term));
1.5       millert   950:
1.8     ! millert   951:     (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n",
        !           952:        NUM_BOOLEANS(term) - BOOLCOUNT);
        !           953:     (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n",
        !           954:        NUM_NUMBERS(term) - NUMCOUNT);
        !           955:     (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n",
        !           956:        NUM_STRINGS(term) - STRCOUNT);
1.5       millert   957:
                    958:     (void) printf("#endif /* NCURSES_XNAMES */\n");
                    959: #endif /* NCURSES_XNAMES */
                    960:     (void) printf("\t%s\n", R_CURL);
                    961: }
                    962:
1.1       millert   963: /***************************************************************************
                    964:  *
                    965:  * Main sequence
                    966:  *
                    967:  ***************************************************************************/
                    968:
1.8     ! millert   969: int
        !           970: main(int argc, char *argv[])
1.1       millert   971: {
1.8     ! millert   972:     char *terminal, *firstdir, *restdir;
        !           973:     /* Avoid "local data >32k" error with mwcc */
        !           974:     /* Also avoid overflowing smaller stacks on systems like AmigaOS */
        !           975:     path *tfile = malloc(sizeof(path) * MAXTERMS);
        !           976:     int c, i, len;
        !           977:     bool formatted = FALSE;
        !           978:     bool filecompare = FALSE;
        !           979:     int initdump = 0;
        !           980:     bool init_analyze = FALSE;
        !           981:     bool limited = TRUE;
        !           982:
        !           983:     if ((terminal = getenv("TERM")) == NULL) {
        !           984:        (void) fprintf(stderr,
        !           985:            "infocmp: environment variable TERM not set\n");
        !           986:        return EXIT_FAILURE;
        !           987:     }
1.1       millert   988:
1.8     ! millert   989:     /* where is the terminfo database location going to default to? */
        !           990:     restdir = firstdir = 0;
        !           991:
        !           992:     while ((c = getopt(argc, argv, "deEcCfFGgIinlLprR:s:uv:Vw:A:B:1T")) != EOF)
        !           993:        switch (c) {
        !           994:        case 'd':
        !           995:            compare = C_DIFFERENCE;
        !           996:            break;
1.1       millert   997:
1.8     ! millert   998:        case 'e':
        !           999:            initdump |= 1;
        !          1000:            break;
1.1       millert  1001:
1.8     ! millert  1002:        case 'E':
        !          1003:            initdump |= 2;
        !          1004:            break;
1.1       millert  1005:
1.8     ! millert  1006:        case 'c':
        !          1007:            compare = C_COMMON;
        !          1008:            break;
1.5       millert  1009:
1.8     ! millert  1010:        case 'C':
        !          1011:            outform = F_TERMCAP;
        !          1012:            tversion = "BSD";
        !          1013:            if (sortmode == S_DEFAULT)
        !          1014:                sortmode = S_TERMCAP;
        !          1015:            break;
1.1       millert  1016:
1.8     ! millert  1017:        case 'f':
        !          1018:            formatted = TRUE;
        !          1019:            break;
1.1       millert  1020:
1.8     ! millert  1021:        case 'G':
        !          1022:            numbers = 1;
        !          1023:            break;
1.1       millert  1024:
1.8     ! millert  1025:        case 'g':
        !          1026:            numbers = -1;
        !          1027:            break;
1.1       millert  1028:
1.8     ! millert  1029:        case 'F':
        !          1030:            filecompare = TRUE;
        !          1031:            break;
1.3       millert  1032:
1.8     ! millert  1033:        case 'I':
        !          1034:            outform = F_TERMINFO;
        !          1035:            if (sortmode == S_DEFAULT)
        !          1036:                sortmode = S_VARIABLE;
        !          1037:            tversion = 0;
        !          1038:            break;
1.1       millert  1039:
1.8     ! millert  1040:        case 'i':
        !          1041:            init_analyze = TRUE;
        !          1042:            break;
1.1       millert  1043:
1.8     ! millert  1044:        case 'l':
        !          1045:            outform = F_TERMINFO;
        !          1046:            break;
1.1       millert  1047:
1.8     ! millert  1048:        case 'L':
        !          1049:            outform = F_VARIABLE;
        !          1050:            if (sortmode == S_DEFAULT)
        !          1051:                sortmode = S_VARIABLE;
        !          1052:            break;
1.1       millert  1053:
1.8     ! millert  1054:        case 'n':
        !          1055:            compare = C_NAND;
        !          1056:            break;
1.1       millert  1057:
1.8     ! millert  1058:        case 'p':
        !          1059:            ignorepads = TRUE;
        !          1060:            break;
1.1       millert  1061:
1.8     ! millert  1062:        case 'r':
        !          1063:            tversion = 0;
        !          1064:            limited = FALSE;
        !          1065:            break;
1.1       millert  1066:
1.8     ! millert  1067:        case 'R':
        !          1068:            tversion = optarg;
        !          1069:            break;
1.1       millert  1070:
1.8     ! millert  1071:        case 's':
        !          1072:            if (*optarg == 'd')
        !          1073:                sortmode = S_NOSORT;
        !          1074:            else if (*optarg == 'i')
        !          1075:                sortmode = S_TERMINFO;
        !          1076:            else if (*optarg == 'l')
        !          1077:                sortmode = S_VARIABLE;
        !          1078:            else if (*optarg == 'c')
        !          1079:                sortmode = S_TERMCAP;
        !          1080:            else {
        !          1081:                (void) fprintf(stderr,
        !          1082:                    "infocmp: unknown sort mode\n");
        !          1083:                return EXIT_FAILURE;
        !          1084:            }
        !          1085:            break;
1.1       millert  1086:
1.8     ! millert  1087:        case 'u':
        !          1088:            compare = C_USEALL;
        !          1089:            break;
1.1       millert  1090:
1.8     ! millert  1091:        case 'v':
        !          1092:            itrace = atoi(optarg);
        !          1093:            set_trace_level(itrace);
        !          1094:            break;
1.1       millert  1095:
1.8     ! millert  1096:        case 'V':
        !          1097:            (void) fputs(NCURSES_VERSION, stdout);
        !          1098:            putchar('\n');
        !          1099:            ExitProgram(EXIT_SUCCESS);
1.1       millert  1100:
1.8     ! millert  1101:        case 'w':
        !          1102:            mwidth = atoi(optarg);
        !          1103:            break;
1.1       millert  1104:
1.8     ! millert  1105:        case 'A':
        !          1106:            firstdir = optarg;
        !          1107:            break;
1.1       millert  1108:
1.8     ! millert  1109:        case 'B':
        !          1110:            restdir = optarg;
        !          1111:            break;
1.1       millert  1112:
1.8     ! millert  1113:        case '1':
        !          1114:            mwidth = 0;
        !          1115:            break;
1.1       millert  1116:
1.8     ! millert  1117:        case 'T':
        !          1118:            limited = FALSE;
        !          1119:            break;
        !          1120:        default:
        !          1121:            usage();
        !          1122:        }
1.1       millert  1123:
1.8     ! millert  1124:     /* by default, sort by terminfo name */
        !          1125:     if (sortmode == S_DEFAULT)
        !          1126:        sortmode = S_TERMINFO;
1.1       millert  1127:
1.8     ! millert  1128:     /* set up for display */
        !          1129:     dump_init(tversion, outform, sortmode, mwidth, itrace, formatted);
1.1       millert  1130:
1.8     ! millert  1131:     /* make sure we have at least one terminal name to work with */
        !          1132:     if (optind >= argc)
        !          1133:        argv[argc++] = terminal;
1.1       millert  1134:
1.8     ! millert  1135:     /* if user is after a comparison, make sure we have two entries */
        !          1136:     if (compare != C_DEFAULT && optind >= argc - 1)
        !          1137:        argv[argc++] = terminal;
1.1       millert  1138:
1.8     ! millert  1139:     /* exactly two terminal names with no options means do -d */
        !          1140:     if (argc - optind == 2 && compare == C_DEFAULT)
        !          1141:        compare = C_DIFFERENCE;
1.1       millert  1142:
1.8     ! millert  1143:     if (!filecompare) {
        !          1144:        /* grab the entries */
        !          1145:        termcount = 0;
        !          1146:        for (; optind < argc; optind++) {
        !          1147:            if (termcount >= MAXTERMS) {
        !          1148:                (void) fprintf(stderr,
        !          1149:                    "infocmp: too many terminal type arguments\n");
        !          1150:                return EXIT_FAILURE;
        !          1151:            } else {
        !          1152:                const char *directory = termcount ? restdir : firstdir;
        !          1153:                int status;
        !          1154:
        !          1155:                tname[termcount] = argv[optind];
        !          1156:
        !          1157:                if (directory) {
        !          1158:                    (void) sprintf(tfile[termcount], "%s/%c/%s",
        !          1159:                        directory,
        !          1160:                        *argv[optind], argv[optind]);
        !          1161:                    if (itrace)
        !          1162:                        (void) fprintf(stderr,
        !          1163:                            "infocmp: reading entry %s from file %s\n",
        !          1164:                            argv[optind], tfile[termcount]);
1.1       millert  1165:
1.8     ! millert  1166:                    status = _nc_read_file_entry(tfile[termcount],
        !          1167:                        &term[termcount]);
        !          1168:                } else {
        !          1169:                    if (itrace)
1.1       millert  1170:                        (void) fprintf(stderr,
1.8     ! millert  1171:                            "infocmp: reading entry %s from system directories %s\n",
        !          1172:                            argv[optind], tname[termcount]);
        !          1173:
        !          1174:                    status = _nc_read_entry(tname[termcount],
        !          1175:                        tfile[termcount],
        !          1176:                        &term[termcount]);
        !          1177:                    directory = TERMINFO;       /* for error message */
        !          1178:                }
        !          1179:
        !          1180:                if (status <= 0) {
        !          1181:                    (void) fprintf(stderr,
        !          1182:                        "infocmp: couldn't open terminfo file %s.\n",
        !          1183:                        tfile[termcount]);
        !          1184:                    return EXIT_FAILURE;
1.1       millert  1185:                }
1.8     ! millert  1186:                termcount++;
1.1       millert  1187:            }
1.8     ! millert  1188:        }
1.1       millert  1189:
1.2       millert  1190: #if NCURSES_XNAMES
1.8     ! millert  1191:        if (termcount > 1)
        !          1192:            _nc_align_termtype(&term[0], &term[1]);
1.2       millert  1193: #endif
                   1194:
1.8     ! millert  1195:        /* dump as C initializer for the terminal type */
        !          1196:        if (initdump) {
        !          1197:            if (initdump & 1)
        !          1198:                dump_termtype();
        !          1199:            if (initdump & 2)
        !          1200:                dump_initializers();
        !          1201:            ExitProgram(EXIT_SUCCESS);
        !          1202:        }
1.1       millert  1203:
1.8     ! millert  1204:        /* analyze the init strings */
        !          1205:        if (init_analyze) {
1.1       millert  1206: #undef CUR
                   1207: #define CUR    term[0].
1.8     ! millert  1208:            analyze_string("is1", init_1string, &term[0]);
        !          1209:            analyze_string("is2", init_2string, &term[0]);
        !          1210:            analyze_string("is3", init_3string, &term[0]);
        !          1211:            analyze_string("rs1", reset_1string, &term[0]);
        !          1212:            analyze_string("rs2", reset_2string, &term[0]);
        !          1213:            analyze_string("rs3", reset_3string, &term[0]);
        !          1214:            analyze_string("smcup", enter_ca_mode, &term[0]);
        !          1215:            analyze_string("rmcup", exit_ca_mode, &term[0]);
1.1       millert  1216: #undef CUR
1.8     ! millert  1217:            ExitProgram(EXIT_SUCCESS);
        !          1218:        }
1.1       millert  1219:
1.8     ! millert  1220:        /*
        !          1221:         * Here's where the real work gets done
        !          1222:         */
        !          1223:        switch (compare) {
        !          1224:        case C_DEFAULT:
        !          1225:            if (itrace)
        !          1226:                (void) fprintf(stderr,
        !          1227:                    "infocmp: about to dump %s\n",
        !          1228:                    tname[0]);
        !          1229:            (void) printf("#\tReconstructed via infocmp from file: %s\n",
        !          1230:                tfile[0]);
        !          1231:            len = dump_entry(&term[0], limited, numbers, NULL);
        !          1232:            putchar('\n');
        !          1233:            if (itrace)
        !          1234:                (void) fprintf(stderr, "infocmp: length %d\n", len);
        !          1235:            break;
1.1       millert  1236:
1.8     ! millert  1237:        case C_DIFFERENCE:
        !          1238:            if (itrace)
        !          1239:                (void) fprintf(stderr, "infocmp: dumping differences\n");
        !          1240:            (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
        !          1241:            compare_entry(compare_predicate, term);
        !          1242:            break;
1.1       millert  1243:
1.8     ! millert  1244:        case C_COMMON:
        !          1245:            if (itrace)
        !          1246:                (void) fprintf(stderr,
        !          1247:                    "infocmp: dumping common capabilities\n");
        !          1248:            (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
        !          1249:            compare_entry(compare_predicate, term);
        !          1250:            break;
1.1       millert  1251:
1.8     ! millert  1252:        case C_NAND:
        !          1253:            if (itrace)
        !          1254:                (void) fprintf(stderr,
        !          1255:                    "infocmp: dumping differences\n");
        !          1256:            (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
        !          1257:            compare_entry(compare_predicate, term);
        !          1258:            break;
1.1       millert  1259:
1.8     ! millert  1260:        case C_USEALL:
        !          1261:            if (itrace)
        !          1262:                (void) fprintf(stderr, "infocmp: dumping use entry\n");
        !          1263:            len = dump_entry(&term[0], limited, numbers, use_predicate);
        !          1264:            for (i = 1; i < termcount; i++)
        !          1265:                len += dump_uses(tname[i], !(outform == F_TERMCAP || outform
        !          1266:                        == F_TCONVERR));
        !          1267:            putchar('\n');
        !          1268:            if (itrace)
        !          1269:                (void) fprintf(stderr, "infocmp: length %d\n", len);
        !          1270:            break;
1.1       millert  1271:        }
1.8     ! millert  1272:     } else if (compare == C_USEALL)
        !          1273:        (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
        !          1274:     else if (compare == C_DEFAULT)
        !          1275:        (void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
        !          1276:     else if (argc - optind != 2)
        !          1277:        (void) fprintf(stderr,
        !          1278:            "File comparison needs exactly two file arguments.\n");
        !          1279:     else
        !          1280:        file_comparison(argc - optind, argv + optind);
1.1       millert  1281:
1.8     ! millert  1282:     ExitProgram(EXIT_SUCCESS);
1.1       millert  1283: }
                   1284:
                   1285: /* infocmp.c ends here */