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