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