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