Annotation of src/usr.bin/infocmp/infocmp.c, Revision 1.18
1.18 ! ray 1: /* $OpenBSD: infocmp.c,v 1.17 2003/04/08 19:08:58 deraadt 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.13 millert 46: MODULE_ID("$From: infocmp.c,v 1.60 2001/02/24 22:03: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 */
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;
1.10 millert 71: static const char *bool_sep = ":";
72: static const char *s_absent = "NULL";
73: static const 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.11 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 */
1.11 millert 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 *
1.16 deraadt 106: canonical_name(char *ptr, char *buf, size_t bufl)
1.1 millert 107: /* extract the terminal type's primary name */
108: {
1.8 millert 109: char *bp;
1.1 millert 110:
1.16 deraadt 111: (void) strlcpy(buf, ptr, bufl);
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:
1.10 millert 288: static const char *
1.9 millert 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
1.16 deraadt 307: dump_numeric(int val, char *buf, size_t bufl)
1.9 millert 308: /* display the value of a boolean capability */
309: {
310: switch (val) {
311: case ABSENT_NUMERIC:
1.16 deraadt 312: strlcpy(buf, s_absent, bufl);
1.9 millert 313: break;
314: case CANCELLED_NUMERIC:
1.16 deraadt 315: strlcpy(buf, s_cancel, bufl);
1.9 millert 316: break;
317: default:
1.16 deraadt 318: snprintf(buf, bufl, "%d", val);
1.9 millert 319: break;
320: }
321: }
322:
323: static void
1.16 deraadt 324: dump_string(char *val, char *buf, size_t bufl)
1.9 millert 325: /* display the value of a string capability */
326: {
327: if (val == ABSENT_STRING)
1.16 deraadt 328: strlcpy(buf, s_absent, bufl);
1.9 millert 329: else if (val == CANCELLED_STRING)
1.16 deraadt 330: strlcpy(buf, s_cancel, bufl);
1.9 millert 331: else {
1.16 deraadt 332: snprintf(buf, bufl, "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val));
1.9 millert 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.15 mpech 340: ENTRY *e1 = &entries[0];
341: ENTRY *e2 = &entries[1];
1.9 millert 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.11 millert 355: name,
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];
1.16 deraadt 376: dump_numeric(n1, buf1, sizeof buf1);
377: dump_numeric(n2, buf2, sizeof 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)) {
1.16 deraadt 402: dump_string(s1, buf1, sizeof buf1);
403: dump_string(s2, buf2, sizeof 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:
1.16 deraadt 608: (void) strlcpy(buf2, (sp[3 + len] == 'h') ? "DEC+" : "DEC-",
609: sizeof buf2);
1.1 millert 610: (void) strncpy(buf3, sp + 3, len);
611: len += 4;
612: buf3[len] = '\0';
613:
614: ep = strtok(buf3, ";");
615: do {
1.8 millert 616: bool found = FALSE;
617:
618: for (ap = private_modes; ap->from; ap++) {
619: size_t tlen = strlen(ap->from);
1.1 millert 620:
1.8 millert 621: if (strncmp(ap->from, ep, tlen) == 0) {
1.16 deraadt 622: (void) strlcat(buf2, ap->to, sizeof buf2);
1.8 millert 623: found = TRUE;
624: break;
625: }
626: }
627:
628: if (!found)
1.16 deraadt 629: (void) strlcat(buf2, ep, sizeof buf2);
630: (void) strlcat(buf2, ";", sizeof buf2);
1.8 millert 631: } while
1.9 millert 632: ((ep = strtok((char *) 0, ";")));
1.18 ! ray 633: if (buf2[0] != '\0' && buf2[strlen(buf2) - 1] == ';')
! 634: buf2[strlen(buf2) - 1] = '\0';
1.1 millert 635: expansion = buf2;
636: }
637:
638: /* now check for ECMA highlight sequences */
639: if (!expansion
1.8 millert 640: && sp[0] == '\033' && sp[1] == '['
641: && (len = strspn(sp + 2, "0123456789;"))
642: && sp[2 + len] == 'm') {
643: char buf3[MAX_TERMINFO_LENGTH];
1.1 millert 644:
1.16 deraadt 645: (void) strlcpy(buf2, "SGR:", sizeof buf2);
1.1 millert 646: (void) strncpy(buf3, sp + 2, len);
647: len += 3;
648: buf3[len] = '\0';
649:
650: ep = strtok(buf3, ";");
651: do {
1.8 millert 652: bool found = FALSE;
653:
654: for (ap = ecma_highlights; ap->from; ap++) {
655: size_t tlen = strlen(ap->from);
656:
657: if (strncmp(ap->from, ep, tlen) == 0) {
1.16 deraadt 658: (void) strlcat(buf2, ap->to, sizeof buf2);
1.8 millert 659: found = TRUE;
660: break;
661: }
662: }
1.1 millert 663:
1.8 millert 664: if (!found)
1.16 deraadt 665: (void) strlcat(buf2, ep, sizeof buf2);
666: (void) strlcat(buf2, ";", sizeof buf2);
1.8 millert 667: } while
1.9 millert 668: ((ep = strtok((char *) 0, ";")));
1.1 millert 669:
1.18 ! ray 670: if (buf2[0] != '\0' && buf2[strlen(buf2) - 1] == ';')
! 671: buf2[strlen(buf2) - 1] = '\0';
1.1 millert 672: expansion = buf2;
673: }
674: /* now check for scroll region reset */
1.8 millert 675: if (!expansion) {
1.16 deraadt 676: (void) snprintf(buf2, sizeof buf2, "\033[1;%dr", tp->Numbers[2]);
1.1 millert 677: len = strlen(buf2);
678: if (strncmp(buf2, sp, len) == 0)
679: expansion = "RSR";
680: }
681:
682: /* now check for home-down */
1.8 millert 683: if (!expansion) {
1.16 deraadt 684: (void) snprintf(buf2, sizeof buf2, "\033[%d;1H", tp->Numbers[2]);
1.1 millert 685: len = strlen(buf2);
686: if (strncmp(buf2, sp, len) == 0)
1.8 millert 687: expansion = "LL";
1.1 millert 688: }
689:
690: /* now look at the expansion we got, if any */
1.8 millert 691: if (expansion) {
1.17 deraadt 692: (void) snprintf(buf + strlen(buf), sizeof buf - strlen(buf),
693: "{%s}", expansion);
1.1 millert 694: sp += len - 1;
695: continue;
1.8 millert 696: } else {
1.1 millert 697: /* couldn't match anything */
698: buf2[0] = *sp;
699: buf2[1] = '\0';
1.16 deraadt 700: (void) strlcat(buf, TIC_EXPAND(buf2), sizeof buf);
1.1 millert 701: }
702: }
703: (void) printf("%s\n", buf);
704: }
705:
706: /***************************************************************************
707: *
708: * File comparison
709: *
710: ***************************************************************************/
711:
1.8 millert 712: static void
713: file_comparison(int argc, char *argv[])
1.1 millert 714: {
715: #define MAXCOMPARE 2
716: /* someday we may allow comparisons on more files */
1.8 millert 717: int filecount = 0;
718: ENTRY *heads[MAXCOMPARE];
719: ENTRY *qp, *rp;
720: int i, n;
1.1 millert 721:
1.9 millert 722: dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, itrace, FALSE);
1.1 millert 723:
1.8 millert 724: for (n = 0; n < argc && n < MAXCOMPARE; n++) {
1.9 millert 725: if (freopen(argv[n], "r", stdin) == 0)
1.1 millert 726: _nc_err_abort("Can't open %s", argv[n]);
727:
1.9 millert 728: _nc_head = _nc_tail = 0;
1.1 millert 729:
730: /* parse entries out of the source file */
731: _nc_set_source(argv[n]);
732: _nc_read_entry_source(stdin, NULL, TRUE, FALSE, NULLHOOK);
733:
734: if (itrace)
1.8 millert 735: (void) fprintf(stderr, "Resolving file %d...\n", n - 0);
1.1 millert 736:
1.9 millert 737: /* maybe do use resolution */
738: if (!_nc_resolve_uses(!limited)) {
1.1 millert 739: (void) fprintf(stderr,
1.11 millert 740: "There are unresolved use entries in %s:\n",
741: argv[n]);
1.9 millert 742: for_entry_list(qp) {
1.8 millert 743: if (qp->nuses) {
1.9 millert 744: (void) fputs(qp->tterm.term_names, stderr);
745: (void) fputc('\n', stderr);
746: }
1.8 millert 747: }
1.1 millert 748: exit(EXIT_FAILURE);
749: }
750:
751: heads[filecount] = _nc_head;
752: filecount++;
753: }
754:
755: /* OK, all entries are in core. Ready to do the comparison */
756: if (itrace)
757: (void) fprintf(stderr, "Entries are now in core...\n");
758:
1.9 millert 759: /* The entry-matching loop. Sigh, this is intrinsically quadratic. */
1.8 millert 760: for (qp = heads[0]; qp; qp = qp->next) {
1.1 millert 761: for (rp = heads[1]; rp; rp = rp->next)
1.8 millert 762: if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
1.9 millert 763: if (qp->ncrosslinks < MAX_CROSSLINKS)
764: qp->crosslinks[qp->ncrosslinks] = rp;
765: qp->ncrosslinks++;
766:
767: if (rp->ncrosslinks < MAX_CROSSLINKS)
768: rp->crosslinks[rp->ncrosslinks] = qp;
769: rp->ncrosslinks++;
1.1 millert 770: }
771: }
772:
773: /* now we have two circular lists with crosslinks */
774: if (itrace)
775: (void) fprintf(stderr, "Name matches are done...\n");
776:
1.9 millert 777: for (qp = heads[0]; qp; qp = qp->next) {
778: if (qp->ncrosslinks > 1) {
1.1 millert 779: (void) fprintf(stderr,
1.11 millert 780: "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
781: _nc_first_name(qp->tterm.term_names),
782: argv[0],
783: qp->ncrosslinks,
784: argv[1]);
1.9 millert 785: for (i = 0; i < qp->ncrosslinks; i++)
1.1 millert 786: (void) fprintf(stderr,
1.11 millert 787: "\t%s\n",
788: _nc_first_name((qp->crosslinks[i])->tterm.term_names));
1.1 millert 789: }
1.9 millert 790: }
791:
792: for (rp = heads[1]; rp; rp = rp->next) {
793: if (rp->ncrosslinks > 1) {
1.1 millert 794: (void) fprintf(stderr,
1.11 millert 795: "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
796: _nc_first_name(rp->tterm.term_names),
797: argv[1],
798: rp->ncrosslinks,
799: argv[0]);
1.9 millert 800: for (i = 0; i < rp->ncrosslinks; i++)
1.1 millert 801: (void) fprintf(stderr,
1.11 millert 802: "\t%s\n",
803: _nc_first_name((rp->crosslinks[i])->tterm.term_names));
1.1 millert 804: }
1.9 millert 805: }
1.1 millert 806:
807: (void) printf("In file 1 (%s) only:\n", argv[0]);
808: for (qp = heads[0]; qp; qp = qp->next)
1.9 millert 809: if (qp->ncrosslinks == 0)
1.1 millert 810: (void) printf("\t%s\n",
1.11 millert 811: _nc_first_name(qp->tterm.term_names));
1.1 millert 812:
813: (void) printf("In file 2 (%s) only:\n", argv[1]);
814: for (rp = heads[1]; rp; rp = rp->next)
1.9 millert 815: if (rp->ncrosslinks == 0)
1.1 millert 816: (void) printf("\t%s\n",
1.11 millert 817: _nc_first_name(rp->tterm.term_names));
1.1 millert 818:
819: (void) printf("The following entries are equivalent:\n");
1.8 millert 820: for (qp = heads[0]; qp; qp = qp->next) {
1.9 millert 821: rp = qp->crosslinks[0];
822:
823: if (qp->ncrosslinks == 1) {
824: rp = qp->crosslinks[0];
1.1 millert 825:
1.9 millert 826: repair_acsc(&qp->tterm);
827: repair_acsc(&rp->tterm);
828: #if NCURSES_XNAMES
829: _nc_align_termtype(&qp->tterm, &rp->tterm);
830: #endif
831: if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) {
832: char name1[NAMESIZE], name2[NAMESIZE];
1.1 millert 833:
1.16 deraadt 834: (void) canonical_name(qp->tterm.term_names, name1, sizeof name1);
835: (void) canonical_name(rp->tterm.term_names, name2, sizeof name2);
1.1 millert 836:
1.9 millert 837: (void) printf("%s = %s\n", name1, name2);
838: }
1.1 millert 839: }
840: }
841:
842: (void) printf("Differing entries:\n");
843: termcount = 2;
1.8 millert 844: for (qp = heads[0]; qp; qp = qp->next) {
1.1 millert 845:
1.9 millert 846: if (qp->ncrosslinks == 1) {
847: rp = qp->crosslinks[0];
1.2 millert 848: #if NCURSES_XNAMES
1.9 millert 849: /* sorry - we have to do this on each pass */
1.2 millert 850: _nc_align_termtype(&qp->tterm, &rp->tterm);
851: #endif
1.9 millert 852: if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) {
853: char name1[NAMESIZE], name2[NAMESIZE];
1.1 millert 854:
1.9 millert 855: entries[0] = *qp;
856: entries[1] = *rp;
1.1 millert 857:
1.16 deraadt 858: (void) canonical_name(qp->tterm.term_names, name1, sizeof name1);
859: (void) canonical_name(rp->tterm.term_names, name2, sizeof name2);
1.1 millert 860:
1.9 millert 861: switch (compare) {
862: case C_DIFFERENCE:
863: if (itrace)
864: (void) fprintf(stderr,
1.11 millert 865: "infocmp: dumping differences\n");
1.9 millert 866: (void) printf("comparing %s to %s.\n", name1, name2);
867: compare_entry(compare_predicate, &entries->tterm, quiet);
868: break;
1.1 millert 869:
1.9 millert 870: case C_COMMON:
871: if (itrace)
872: (void) fprintf(stderr,
1.11 millert 873: "infocmp: dumping common capabilities\n");
1.9 millert 874: (void) printf("comparing %s to %s.\n", name1, name2);
875: compare_entry(compare_predicate, &entries->tterm, quiet);
876: break;
1.1 millert 877:
1.9 millert 878: case C_NAND:
879: if (itrace)
880: (void) fprintf(stderr,
1.11 millert 881: "infocmp: dumping differences\n");
1.9 millert 882: (void) printf("comparing %s to %s.\n", name1, name2);
883: compare_entry(compare_predicate, &entries->tterm, quiet);
884: break;
1.1 millert 885:
1.9 millert 886: }
1.1 millert 887: }
888: }
889: }
890: }
891:
1.8 millert 892: static void
893: usage(void)
1.1 millert 894: {
1.8 millert 895: static const char *tbl[] =
896: {
897: "Usage: infocmp [options] [-A directory] [-B directory] [termname...]"
898: ,""
899: ,"Options:"
900: ," -1 print single-column"
901: ," -C use termcap-names"
902: ," -F compare terminfo-files"
903: ," -I use terminfo-names"
904: ," -L use long names"
905: ," -R subset (see manpage)"
906: ," -T eliminate size limits (test)"
907: ," -V print version"
1.10 millert 908: #if NCURSES_XNAMES
909: ," -a with -F, list commented-out caps"
910: #endif
1.8 millert 911: ," -c list common capabilities"
912: ," -d list different capabilities"
913: ," -e format output for C initializer"
914: ," -E format output as C tables"
915: ," -f with -1, format complex strings"
916: ," -G format %{number} to %'char'"
917: ," -g format %'char' to %{number}"
918: ," -i analyze initialization/reset"
919: ," -l output terminfo names"
920: ," -n list capabilities in neither"
921: ," -p ignore padding specifiers"
1.9 millert 922: ," -q brief listing, removes headers"
1.8 millert 923: ," -r with -C, output in termcap form"
1.9 millert 924: ," -r with -F, resolve use-references"
1.8 millert 925: ," -s [d|i|l|c] sort fields"
926: ," -u produce source with 'use='"
927: ," -v number (verbose)"
928: ," -w number (width)"
929: };
930: const size_t first = 3;
1.11 millert 931: const size_t last = SIZEOF(tbl);
1.8 millert 932: const size_t left = (last - first + 1) / 2 + first;
933: size_t n;
934:
935: for (n = 0; n < left; n++) {
936: size_t m = (n < first) ? last : n + left - first;
937: if (m < last)
938: fprintf(stderr, "%-40.40s%s\n", tbl[n], tbl[m]);
939: else
940: fprintf(stderr, "%s\n", tbl[n]);
941: }
942: exit(EXIT_FAILURE);
1.1 millert 943: }
944:
1.8 millert 945: static char *
946: name_initializer(const char *type)
1.5 millert 947: {
948: static char *initializer;
1.16 deraadt 949: static size_t len;
1.5 millert 950: char *s;
951:
1.16 deraadt 952: if (initializer == 0) {
953: len = strlen(entries->tterm.term_names) + 20;
954: initializer = (char *) malloc(len);
955: }
1.5 millert 956:
1.16 deraadt 957: (void) snprintf(initializer, len, "%s_data_%s", type, entries->tterm.term_names);
1.8 millert 958: for (s = initializer; *s != 0 && *s != '|'; s++) {
1.12 millert 959: if (!isalnum(CharOf(*s)))
1.5 millert 960: *s = '_';
961: }
962: *s = 0;
963: return initializer;
964: }
965:
966: /* dump C initializers for the terminal type */
1.8 millert 967: static void
1.9 millert 968: dump_initializers(TERMTYPE * term)
1.5 millert 969: {
1.8 millert 970: int n;
1.5 millert 971: const char *str = 0;
1.8 millert 972: int size;
1.5 millert 973:
1.6 millert 974: (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL);
1.5 millert 975:
1.8 millert 976: for_each_boolean(n, term) {
977: switch ((int) (term->Booleans[n])) {
1.5 millert 978: case TRUE:
979: str = "TRUE";
980: break;
981:
982: case FALSE:
983: str = "FALSE";
984: break;
985:
986: case ABSENT_BOOLEAN:
987: str = "ABSENT_BOOLEAN";
988: break;
989:
990: case CANCELLED_BOOLEAN:
991: str = "CANCELLED_BOOLEAN";
992: break;
993: }
994: (void) printf("\t/* %3d: %-8s */\t%s,\n",
1.11 millert 995: n, ExtBoolname(term, n, boolnames), str);
1.5 millert 996: }
997: (void) printf("%s;\n", R_CURL);
998:
999: (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL);
1000:
1.8 millert 1001: for_each_number(n, term) {
1002: char buf[BUFSIZ];
1003: switch (term->Numbers[n]) {
1.5 millert 1004: case ABSENT_NUMERIC:
1005: str = "ABSENT_NUMERIC";
1006: break;
1007: case CANCELLED_NUMERIC:
1008: str = "CANCELLED_NUMERIC";
1009: break;
1010: default:
1.16 deraadt 1011: snprintf(buf, sizeof buf, "%d", term->Numbers[n]);
1.5 millert 1012: str = buf;
1013: break;
1014: }
1.11 millert 1015: (void) printf("\t/* %3d: %-8s */\t%s,\n", n,
1016: ExtNumname(term, n, numnames), str);
1.5 millert 1017: }
1018: (void) printf("%s;\n", R_CURL);
1019:
1020: size = sizeof(TERMTYPE)
1021: + (NUM_BOOLEANS(term) * sizeof(term->Booleans[0]))
1022: + (NUM_NUMBERS(term) * sizeof(term->Numbers[0]));
1023:
1024: (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL);
1025:
1.8 millert 1026: for_each_string(n, term) {
1.9 millert 1027: char buf[MAX_STRING], *sp, *tp;
1.5 millert 1028:
1029: if (term->Strings[n] == ABSENT_STRING)
1030: str = "ABSENT_STRING";
1031: else if (term->Strings[n] == CANCELLED_STRING)
1032: str = "CANCELLED_STRING";
1.8 millert 1033: else {
1.5 millert 1034: tp = buf;
1035: *tp++ = '"';
1.9 millert 1036: for (sp = term->Strings[n];
1.11 millert 1037: *sp != 0 && (tp - buf) < MAX_STRING - 6;
1038: sp++) {
1.12 millert 1039: if (isascii(CharOf(*sp))
1040: && isprint(CharOf(*sp))
1041: && *sp != '\\'
1042: && *sp != '"')
1.5 millert 1043: *tp++ = *sp;
1.8 millert 1044: else {
1.17 deraadt 1045: (void) snprintf(tp, buf + sizeof buf - tp, "\\%03o", CharOf(*sp));
1.5 millert 1046: tp += 4;
1047: }
1048: }
1049: *tp++ = '"';
1050: *tp = '\0';
1051: size += (strlen(term->Strings[n]) + 1);
1052: str = buf;
1053: }
1054: #if NCURSES_XNAMES
1.8 millert 1055: if (n == STRCOUNT) {
1.5 millert 1056: (void) printf("%s;\n", R_CURL);
1057:
1.8 millert 1058: (void) printf("static char * %s[] = %s\n",
1.11 millert 1059: name_initializer("string_ext"), L_CURL);
1.5 millert 1060: }
1061: #endif
1.11 millert 1062: (void) printf("\t/* %3d: %-8s */\t%s,\n", n,
1063: ExtStrname(term, n, strnames), str);
1.5 millert 1064: }
1065: (void) printf("%s;\n", R_CURL);
1066: }
1067:
1068: /* dump C initializers for the terminal type */
1.8 millert 1069: static void
1.9 millert 1070: dump_termtype(TERMTYPE * term)
1.5 millert 1071: {
1072: (void) printf("\t%s\n\t\t\"%s\",\n", L_CURL, term->term_names);
1073: (void) printf("\t\t(char *)0,\t/* pointer to string table */\n");
1074:
1075: (void) printf("\t\t%s,\n", name_initializer("bool"));
1076: (void) printf("\t\t%s,\n", name_initializer("number"));
1077:
1078: (void) printf("\t\t%s,\n", name_initializer("string"));
1079:
1080: #if NCURSES_XNAMES
1081: (void) printf("#if NCURSES_XNAMES\n");
1082: (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n");
1083: (void) printf("\t\t%s,\t/* ...corresponding names */\n",
1.11 millert 1084: (NUM_STRINGS(term) != STRCOUNT)
1085: ? name_initializer("string_ext")
1086: : "(char **)0");
1.5 millert 1087:
1088: (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term));
1.8 millert 1089: (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term));
1090: (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term));
1.5 millert 1091:
1.8 millert 1092: (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n",
1.11 millert 1093: NUM_BOOLEANS(term) - BOOLCOUNT);
1.8 millert 1094: (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n",
1.11 millert 1095: NUM_NUMBERS(term) - NUMCOUNT);
1.8 millert 1096: (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n",
1.11 millert 1097: NUM_STRINGS(term) - STRCOUNT);
1.5 millert 1098:
1099: (void) printf("#endif /* NCURSES_XNAMES */\n");
1100: #endif /* NCURSES_XNAMES */
1101: (void) printf("\t%s\n", R_CURL);
1102: }
1103:
1.11 millert 1104: static int
1105: optarg_to_number(void)
1106: {
1107: char *temp = 0;
1108: long value = strtol(optarg, &temp, 0);
1109:
1110: if (temp == 0 || temp == optarg || *temp != 0) {
1111: fprintf(stderr, "Expected a number, not \"%s\"\n", optarg);
1112: exit(EXIT_FAILURE);
1113: }
1114: return (int) value;
1115: }
1116:
1.1 millert 1117: /***************************************************************************
1118: *
1119: * Main sequence
1120: *
1121: ***************************************************************************/
1122:
1.8 millert 1123: int
1124: main(int argc, char *argv[])
1.1 millert 1125: {
1.8 millert 1126: char *terminal, *firstdir, *restdir;
1127: /* Avoid "local data >32k" error with mwcc */
1128: /* Also avoid overflowing smaller stacks on systems like AmigaOS */
1.17 deraadt 1129: size_t tlen = sizeof(path) * MAXTERMS;
1130: path *tfile = (path *) malloc(tlen);
1.8 millert 1131: int c, i, len;
1132: bool formatted = FALSE;
1133: bool filecompare = FALSE;
1134: int initdump = 0;
1135: bool init_analyze = FALSE;
1136:
1.9 millert 1137: if ((terminal = getenv("TERM")) == 0) {
1.8 millert 1138: (void) fprintf(stderr,
1.11 millert 1139: "infocmp: environment variable TERM not set\n");
1.8 millert 1140: return EXIT_FAILURE;
1141: }
1.1 millert 1142:
1.8 millert 1143: /* where is the terminfo database location going to default to? */
1144: restdir = firstdir = 0;
1145:
1.14 mpech 1146: while ((c = getopt(argc, argv, "adeEcCfFGgIinlLpqrR:s:uv:Vw:A:B:1T")) != -1)
1.8 millert 1147: switch (c) {
1.10 millert 1148: #if NCURSES_XNAMES
1149: case 'a':
1150: _nc_disable_period = TRUE;
1151: use_extended_names(TRUE);
1152: break;
1153: #endif
1.8 millert 1154: case 'd':
1155: compare = C_DIFFERENCE;
1156: break;
1.1 millert 1157:
1.8 millert 1158: case 'e':
1159: initdump |= 1;
1160: break;
1.1 millert 1161:
1.8 millert 1162: case 'E':
1163: initdump |= 2;
1164: break;
1.1 millert 1165:
1.8 millert 1166: case 'c':
1167: compare = C_COMMON;
1168: break;
1.5 millert 1169:
1.8 millert 1170: case 'C':
1171: outform = F_TERMCAP;
1172: tversion = "BSD";
1173: if (sortmode == S_DEFAULT)
1174: sortmode = S_TERMCAP;
1175: break;
1.1 millert 1176:
1.8 millert 1177: case 'f':
1178: formatted = TRUE;
1179: break;
1.1 millert 1180:
1.8 millert 1181: case 'G':
1182: numbers = 1;
1183: break;
1.1 millert 1184:
1.8 millert 1185: case 'g':
1186: numbers = -1;
1187: break;
1.1 millert 1188:
1.8 millert 1189: case 'F':
1190: filecompare = TRUE;
1191: break;
1.3 millert 1192:
1.8 millert 1193: case 'I':
1194: outform = F_TERMINFO;
1195: if (sortmode == S_DEFAULT)
1196: sortmode = S_VARIABLE;
1197: tversion = 0;
1198: break;
1.1 millert 1199:
1.8 millert 1200: case 'i':
1201: init_analyze = TRUE;
1202: break;
1.1 millert 1203:
1.8 millert 1204: case 'l':
1205: outform = F_TERMINFO;
1206: break;
1.1 millert 1207:
1.8 millert 1208: case 'L':
1209: outform = F_VARIABLE;
1210: if (sortmode == S_DEFAULT)
1211: sortmode = S_VARIABLE;
1212: break;
1.1 millert 1213:
1.8 millert 1214: case 'n':
1215: compare = C_NAND;
1216: break;
1.1 millert 1217:
1.8 millert 1218: case 'p':
1219: ignorepads = TRUE;
1220: break;
1.1 millert 1221:
1.9 millert 1222: case 'q':
1223: quiet = TRUE;
1224: s_absent = "-";
1225: s_cancel = "@";
1226: bool_sep = ", ";
1227: break;
1228:
1.8 millert 1229: case 'r':
1230: tversion = 0;
1231: limited = FALSE;
1232: break;
1.1 millert 1233:
1.8 millert 1234: case 'R':
1235: tversion = optarg;
1236: break;
1.1 millert 1237:
1.8 millert 1238: case 's':
1239: if (*optarg == 'd')
1240: sortmode = S_NOSORT;
1241: else if (*optarg == 'i')
1242: sortmode = S_TERMINFO;
1243: else if (*optarg == 'l')
1244: sortmode = S_VARIABLE;
1245: else if (*optarg == 'c')
1246: sortmode = S_TERMCAP;
1247: else {
1248: (void) fprintf(stderr,
1.11 millert 1249: "infocmp: unknown sort mode\n");
1.8 millert 1250: return EXIT_FAILURE;
1251: }
1252: break;
1.1 millert 1253:
1.8 millert 1254: case 'u':
1255: compare = C_USEALL;
1256: break;
1.1 millert 1257:
1.8 millert 1258: case 'v':
1.11 millert 1259: itrace = optarg_to_number();
1.8 millert 1260: set_trace_level(itrace);
1261: break;
1.1 millert 1262:
1.8 millert 1263: case 'V':
1.11 millert 1264: puts(curses_version());
1.8 millert 1265: ExitProgram(EXIT_SUCCESS);
1.1 millert 1266:
1.8 millert 1267: case 'w':
1.11 millert 1268: mwidth = optarg_to_number();
1.8 millert 1269: break;
1.1 millert 1270:
1.8 millert 1271: case 'A':
1272: firstdir = optarg;
1273: break;
1.1 millert 1274:
1.8 millert 1275: case 'B':
1276: restdir = optarg;
1277: break;
1.1 millert 1278:
1.8 millert 1279: case '1':
1280: mwidth = 0;
1281: break;
1.1 millert 1282:
1.8 millert 1283: case 'T':
1284: limited = FALSE;
1285: break;
1286: default:
1287: usage();
1288: }
1.1 millert 1289:
1.8 millert 1290: /* by default, sort by terminfo name */
1291: if (sortmode == S_DEFAULT)
1292: sortmode = S_TERMINFO;
1.1 millert 1293:
1.8 millert 1294: /* set up for display */
1295: dump_init(tversion, outform, sortmode, mwidth, itrace, formatted);
1.1 millert 1296:
1.8 millert 1297: /* make sure we have at least one terminal name to work with */
1298: if (optind >= argc)
1299: argv[argc++] = terminal;
1.1 millert 1300:
1.8 millert 1301: /* if user is after a comparison, make sure we have two entries */
1302: if (compare != C_DEFAULT && optind >= argc - 1)
1303: argv[argc++] = terminal;
1.1 millert 1304:
1.8 millert 1305: /* exactly two terminal names with no options means do -d */
1306: if (argc - optind == 2 && compare == C_DEFAULT)
1307: compare = C_DIFFERENCE;
1.1 millert 1308:
1.8 millert 1309: if (!filecompare) {
1310: /* grab the entries */
1311: termcount = 0;
1312: for (; optind < argc; optind++) {
1313: if (termcount >= MAXTERMS) {
1314: (void) fprintf(stderr,
1.11 millert 1315: "infocmp: too many terminal type arguments\n");
1.8 millert 1316: return EXIT_FAILURE;
1317: } else {
1318: const char *directory = termcount ? restdir : firstdir;
1319: int status;
1320:
1321: tname[termcount] = argv[optind];
1322:
1323: if (directory) {
1.17 deraadt 1324: (void) snprintf(tfile[termcount],
1325: tlen - termcount,
1326: "%s/%c/%s",
1.11 millert 1327: directory,
1328: *argv[optind], argv[optind]);
1.8 millert 1329: if (itrace)
1330: (void) fprintf(stderr,
1.11 millert 1331: "infocmp: reading entry %s from file %s\n",
1332: argv[optind], tfile[termcount]);
1.1 millert 1333:
1.8 millert 1334: status = _nc_read_file_entry(tfile[termcount],
1.11 millert 1335: &entries[termcount].tterm);
1.8 millert 1336: } else {
1337: if (itrace)
1.1 millert 1338: (void) fprintf(stderr,
1.11 millert 1339: "infocmp: reading entry %s from system directories %s\n",
1340: argv[optind], tname[termcount]);
1.8 millert 1341:
1342: status = _nc_read_entry(tname[termcount],
1.11 millert 1343: tfile[termcount],
1344: &entries[termcount].tterm);
1.8 millert 1345: directory = TERMINFO; /* for error message */
1346: }
1347:
1348: if (status <= 0) {
1349: (void) fprintf(stderr,
1.11 millert 1350: "infocmp: couldn't open terminfo file %s.\n",
1351: tfile[termcount]);
1.8 millert 1352: return EXIT_FAILURE;
1.1 millert 1353: }
1.9 millert 1354: repair_acsc(&entries[termcount].tterm);
1.8 millert 1355: termcount++;
1.1 millert 1356: }
1.8 millert 1357: }
1.1 millert 1358:
1.2 millert 1359: #if NCURSES_XNAMES
1.8 millert 1360: if (termcount > 1)
1.9 millert 1361: _nc_align_termtype(&entries[0].tterm, &entries[1].tterm);
1.2 millert 1362: #endif
1363:
1.8 millert 1364: /* dump as C initializer for the terminal type */
1365: if (initdump) {
1366: if (initdump & 1)
1.9 millert 1367: dump_termtype(&entries[0].tterm);
1.8 millert 1368: if (initdump & 2)
1.9 millert 1369: dump_initializers(&entries[0].tterm);
1.8 millert 1370: ExitProgram(EXIT_SUCCESS);
1371: }
1.1 millert 1372:
1.8 millert 1373: /* analyze the init strings */
1374: if (init_analyze) {
1.1 millert 1375: #undef CUR
1.9 millert 1376: #define CUR entries[0].tterm.
1377: analyze_string("is1", init_1string, &entries[0].tterm);
1378: analyze_string("is2", init_2string, &entries[0].tterm);
1379: analyze_string("is3", init_3string, &entries[0].tterm);
1380: analyze_string("rs1", reset_1string, &entries[0].tterm);
1381: analyze_string("rs2", reset_2string, &entries[0].tterm);
1382: analyze_string("rs3", reset_3string, &entries[0].tterm);
1383: analyze_string("smcup", enter_ca_mode, &entries[0].tterm);
1384: analyze_string("rmcup", exit_ca_mode, &entries[0].tterm);
1.1 millert 1385: #undef CUR
1.8 millert 1386: ExitProgram(EXIT_SUCCESS);
1387: }
1.1 millert 1388:
1.8 millert 1389: /*
1390: * Here's where the real work gets done
1391: */
1392: switch (compare) {
1393: case C_DEFAULT:
1394: if (itrace)
1395: (void) fprintf(stderr,
1.11 millert 1396: "infocmp: about to dump %s\n",
1397: tname[0]);
1.8 millert 1398: (void) printf("#\tReconstructed via infocmp from file: %s\n",
1.11 millert 1399: tfile[0]);
1.9 millert 1400: len = dump_entry(&entries[0].tterm, limited, numbers, NULL);
1.8 millert 1401: putchar('\n');
1402: if (itrace)
1403: (void) fprintf(stderr, "infocmp: length %d\n", len);
1404: break;
1.1 millert 1405:
1.8 millert 1406: case C_DIFFERENCE:
1407: if (itrace)
1408: (void) fprintf(stderr, "infocmp: dumping differences\n");
1409: (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1.9 millert 1410: compare_entry(compare_predicate, &entries->tterm, quiet);
1.8 millert 1411: break;
1.1 millert 1412:
1.8 millert 1413: case C_COMMON:
1414: if (itrace)
1415: (void) fprintf(stderr,
1.11 millert 1416: "infocmp: dumping common capabilities\n");
1.8 millert 1417: (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1.9 millert 1418: compare_entry(compare_predicate, &entries->tterm, quiet);
1.8 millert 1419: break;
1.1 millert 1420:
1.8 millert 1421: case C_NAND:
1422: if (itrace)
1423: (void) fprintf(stderr,
1.11 millert 1424: "infocmp: dumping differences\n");
1.8 millert 1425: (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1.9 millert 1426: compare_entry(compare_predicate, &entries->tterm, quiet);
1.8 millert 1427: break;
1.1 millert 1428:
1.8 millert 1429: case C_USEALL:
1430: if (itrace)
1431: (void) fprintf(stderr, "infocmp: dumping use entry\n");
1.9 millert 1432: len = dump_entry(&entries[0].tterm, limited, numbers, use_predicate);
1.8 millert 1433: for (i = 1; i < termcount; i++)
1434: len += dump_uses(tname[i], !(outform == F_TERMCAP || outform
1.11 millert 1435: == F_TCONVERR));
1.8 millert 1436: putchar('\n');
1437: if (itrace)
1438: (void) fprintf(stderr, "infocmp: length %d\n", len);
1439: break;
1.1 millert 1440: }
1.8 millert 1441: } else if (compare == C_USEALL)
1442: (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
1443: else if (compare == C_DEFAULT)
1444: (void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
1445: else if (argc - optind != 2)
1446: (void) fprintf(stderr,
1.11 millert 1447: "File comparison needs exactly two file arguments.\n");
1.8 millert 1448: else
1449: file_comparison(argc - optind, argv + optind);
1.1 millert 1450:
1.8 millert 1451: ExitProgram(EXIT_SUCCESS);
1.1 millert 1452: }
1453:
1454: /* infocmp.c ends here */