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 */