Annotation of src/usr.bin/infocmp/infocmp.c, Revision 1.24
1.24 ! nicm 1: /* $OpenBSD: infocmp.c,v 1.23 2016/08/03 16:32:08 krw Exp $ */
1.1 millert 2:
3: /****************************************************************************
1.24 ! nicm 4: * Copyright 2020-2022,2023 Thomas E. Dickey *
! 5: * Copyright 1998-2016,2017 Free Software Foundation, Inc. *
1.1 millert 6: * *
7: * Permission is hereby granted, free of charge, to any person obtaining a *
8: * copy of this software and associated documentation files (the *
9: * "Software"), to deal in the Software without restriction, including *
10: * without limitation the rights to use, copy, modify, merge, publish, *
11: * distribute, distribute with modifications, sublicense, and/or sell *
12: * copies of the Software, and to permit persons to whom the Software is *
13: * furnished to do so, subject to the following conditions: *
14: * *
15: * The above copyright notice and this permission notice shall be included *
16: * in all copies or substantial portions of the Software. *
17: * *
18: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
19: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
20: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
21: * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
22: * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
23: * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
24: * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
25: * *
26: * Except as contained in this notice, the name(s) of the above copyright *
27: * holders shall not be used in advertising or otherwise to promote the *
28: * sale, use or other dealings in this Software without prior written *
29: * authorization. *
30: ****************************************************************************/
31:
32: /****************************************************************************
33: * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
34: * and: Eric S. Raymond <esr@snark.thyrsus.com> *
1.20 nicm 35: * and: Thomas E. Dickey 1996-on *
1.1 millert 36: ****************************************************************************/
37:
38: /*
39: * infocmp.c -- decompile an entry, or compare two entries
40: * written by Eric S. Raymond
1.20 nicm 41: * and Thomas E Dickey
1.1 millert 42: */
43:
44: #include <progs.priv.h>
45:
46: #include <dump_entry.h>
47:
1.24 ! nicm 48: MODULE_ID("$Id: infocmp.c,v 1.23 2016/08/03 16:32:08 krw Exp $")
1.1 millert 49:
1.9 millert 50: #define MAX_STRING 1024 /* maximum formatted string */
1.1 millert 51:
52: const char *_nc_progname = "infocmp";
53:
1.8 millert 54: typedef char path[PATH_MAX];
1.1 millert 55:
56: /***************************************************************************
57: *
58: * The following control variables, together with the contents of the
59: * terminfo entries, completely determine the actions of the program.
60: *
61: ***************************************************************************/
62:
1.20 nicm 63: static ENTRY *entries; /* terminfo entries */
1.1 millert 64: static int termcount; /* count of terminal entries */
65:
1.9 millert 66: static bool limited = TRUE; /* "-r" option is not set */
67: static bool quiet = FALSE;
1.20 nicm 68: static bool literal = FALSE;
1.10 millert 69: static const char *bool_sep = ":";
70: static const char *s_absent = "NULL";
71: static const char *s_cancel = "NULL";
1.1 millert 72: static const char *tversion; /* terminfo version selected */
1.24 ! nicm 73: static unsigned itrace; /* trace flag for debugging */
1.9 millert 74: static int mwidth = 60;
1.24 ! nicm 75: static int mheight = 65535;
1.3 millert 76: static int numbers = 0; /* format "%'char'" to/from "%{number}" */
1.11 millert 77: static int outform = F_TERMINFO; /* output format */
1.1 millert 78: static int sortmode; /* sort_mode */
79:
80: /* main comparison mode */
81: static int compare;
82: #define C_DEFAULT 0 /* don't force comparison mode */
83: #define C_DIFFERENCE 1 /* list differences between two terminals */
84: #define C_COMMON 2 /* list common capabilities */
85: #define C_NAND 3 /* list capabilities in neither terminal */
86: #define C_USEALL 4 /* generate relative use-form entry */
87: static bool ignorepads; /* ignore pad prefixes when diffing */
88:
89: #if NO_LEAKS
1.24 ! nicm 90:
! 91: typedef struct {
! 92: ENTRY *head;
! 93: ENTRY *tail;
! 94: } ENTERED;
! 95:
! 96: static ENTERED *entered;
! 97:
1.1 millert 98: #undef ExitProgram
1.24 ! nicm 99: static GCC_NORETURN void ExitProgram(int code);
1.20 nicm 100: /* prototype is to get gcc to accept the noreturn attribute */
1.8 millert 101: static void
1.20 nicm 102: ExitProgram(int code)
1.1 millert 103: {
1.24 ! nicm 104: int n;
! 105:
! 106: for (n = 0; n < termcount; ++n) {
! 107: ENTRY *new_head = _nc_head;
! 108: ENTRY *new_tail = _nc_tail;
! 109: _nc_head = entered[n].head;
! 110: _nc_tail = entered[n].tail;
! 111: _nc_free_entries(entered[n].head);
! 112: _nc_head = new_head;
! 113: _nc_tail = new_tail;
! 114: }
1.8 millert 115: _nc_leaks_dump_entry();
1.20 nicm 116: free(entries);
1.24 ! nicm 117: free(entered);
1.20 nicm 118: _nc_free_tic(code);
1.1 millert 119: }
120: #endif
121:
1.24 ! nicm 122: static void
! 123: failed(const char *s)
! 124: {
! 125: perror(s);
! 126: ExitProgram(EXIT_FAILURE);
! 127: }
! 128:
! 129: static void
! 130: canonical_name(char *source, char *target)
1.1 millert 131: /* extract the terminal type's primary name */
132: {
1.24 ! nicm 133: int limit = NAMESIZE;
1.1 millert 134:
1.24 ! nicm 135: while (--limit > 0) {
! 136: char ch = *source++;
! 137: if (ch == '|')
! 138: break;
! 139: *target++ = ch;
! 140: }
! 141: *target = '\0';
! 142: }
1.1 millert 143:
1.24 ! nicm 144: static bool
! 145: no_boolean(int value)
! 146: {
! 147: bool result = (value == ABSENT_BOOLEAN);
! 148: if (!strcmp(s_absent, s_cancel))
! 149: result = !VALID_BOOLEAN(value);
! 150: return result;
! 151: }
! 152:
! 153: static bool
! 154: no_numeric(int value)
! 155: {
! 156: bool result = (value == ABSENT_NUMERIC);
! 157: if (!strcmp(s_absent, s_cancel))
! 158: result = !VALID_NUMERIC(value);
! 159: return result;
! 160: }
! 161:
! 162: static bool
! 163: no_string(const char *const value)
! 164: {
! 165: bool result = (value == ABSENT_STRING);
! 166: if (!strcmp(s_absent, s_cancel))
! 167: result = !VALID_STRING(value);
! 168: return result;
1.1 millert 169: }
170:
171: /***************************************************************************
172: *
173: * Predicates for dump function
174: *
175: ***************************************************************************/
176:
1.8 millert 177: static int
1.20 nicm 178: capcmp(PredIdx idx, const char *s, const char *t)
1.1 millert 179: /* capability comparison function */
180: {
181: if (!VALID_STRING(s) && !VALID_STRING(t))
1.9 millert 182: return (s != t);
1.1 millert 183: else if (!VALID_STRING(s) || !VALID_STRING(t))
1.8 millert 184: return (1);
1.1 millert 185:
1.9 millert 186: if ((idx == acs_chars_index) || !ignorepads)
187: return (strcmp(s, t));
188: else
1.8 millert 189: return (_nc_capcmp(s, t));
1.1 millert 190: }
191:
1.8 millert 192: static int
1.20 nicm 193: use_predicate(unsigned type, PredIdx idx)
1.1 millert 194: /* predicate function to use for use decompilation */
195: {
1.9 millert 196: ENTRY *ep;
1.1 millert 197:
1.8 millert 198: switch (type) {
1.9 millert 199: case BOOLEAN:
200: {
1.8 millert 201: int is_set = FALSE;
1.1 millert 202:
1.8 millert 203: /*
204: * This assumes that multiple use entries are supposed
205: * to contribute the logical or of their boolean capabilities.
206: * This is true if we take the semantics of multiple uses to
207: * be 'each capability gets the first non-default value found
208: * in the sequence of use entries'.
1.9 millert 209: *
210: * Note that cancelled or absent booleans are stored as FALSE,
211: * unlike numbers and strings, whose cancelled/absent state is
212: * recorded in the terminfo database.
1.8 millert 213: */
1.9 millert 214: for (ep = &entries[1]; ep < entries + termcount; ep++)
215: if (ep->tterm.Booleans[idx] == TRUE) {
216: is_set = entries[0].tterm.Booleans[idx];
1.8 millert 217: break;
1.1 millert 218: }
1.9 millert 219: if (is_set != entries[0].tterm.Booleans[idx])
1.8 millert 220: return (!is_set);
221: else
222: return (FAIL);
223: }
1.1 millert 224:
1.9 millert 225: case NUMBER:
226: {
1.8 millert 227: int value = ABSENT_NUMERIC;
1.1 millert 228:
1.8 millert 229: /*
230: * We take the semantics of multiple uses to be 'each
231: * capability gets the first non-default value found
232: * in the sequence of use entries'.
233: */
1.9 millert 234: for (ep = &entries[1]; ep < entries + termcount; ep++)
235: if (VALID_NUMERIC(ep->tterm.Numbers[idx])) {
236: value = ep->tterm.Numbers[idx];
1.8 millert 237: break;
1.1 millert 238: }
239:
1.9 millert 240: if (value != entries[0].tterm.Numbers[idx])
1.8 millert 241: return (value != ABSENT_NUMERIC);
242: else
243: return (FAIL);
244: }
245:
1.9 millert 246: case STRING:
247: {
1.8 millert 248: char *termstr, *usestr = ABSENT_STRING;
1.1 millert 249:
1.9 millert 250: termstr = entries[0].tterm.Strings[idx];
1.1 millert 251:
1.8 millert 252: /*
253: * We take the semantics of multiple uses to be 'each
254: * capability gets the first non-default value found
255: * in the sequence of use entries'.
256: */
1.9 millert 257: for (ep = &entries[1]; ep < entries + termcount; ep++)
258: if (ep->tterm.Strings[idx]) {
259: usestr = ep->tterm.Strings[idx];
1.8 millert 260: break;
261: }
262:
263: if (usestr == ABSENT_STRING && termstr == ABSENT_STRING)
264: return (FAIL);
1.9 millert 265: else if (!usestr || !termstr || capcmp(idx, usestr, termstr))
1.8 millert 266: return (TRUE);
267: else
268: return (FAIL);
1.1 millert 269: }
1.8 millert 270: }
1.1 millert 271:
1.8 millert 272: return (FALSE); /* pacify compiler */
1.1 millert 273: }
274:
1.8 millert 275: static bool
1.9 millert 276: useeq(ENTRY * e1, ENTRY * e2)
277: /* are the use references in two entries equivalent? */
278: {
1.20 nicm 279: unsigned i, j;
1.9 millert 280:
281: if (e1->nuses != e2->nuses)
282: return (FALSE);
283:
284: /* Ugh...this is quadratic again */
285: for (i = 0; i < e1->nuses; i++) {
286: bool foundmatch = FALSE;
287:
288: /* search second entry for given use reference */
289: for (j = 0; j < e2->nuses; j++)
290: if (!strcmp(e1->uses[i].name, e2->uses[j].name)) {
291: foundmatch = TRUE;
292: break;
293: }
294:
295: if (!foundmatch)
296: return (FALSE);
297: }
298:
299: return (TRUE);
300: }
301:
302: static bool
1.24 ! nicm 303: entryeq(TERMTYPE2 *t1, TERMTYPE2 *t2)
1.9 millert 304: /* are two entries equivalent? */
1.1 millert 305: {
1.20 nicm 306: unsigned i;
1.1 millert 307:
1.2 millert 308: for (i = 0; i < NUM_BOOLEANS(t1); i++)
1.1 millert 309: if (t1->Booleans[i] != t2->Booleans[i])
1.8 millert 310: return (FALSE);
1.1 millert 311:
1.2 millert 312: for (i = 0; i < NUM_NUMBERS(t1); i++)
1.1 millert 313: if (t1->Numbers[i] != t2->Numbers[i])
1.8 millert 314: return (FALSE);
1.1 millert 315:
1.2 millert 316: for (i = 0; i < NUM_STRINGS(t1); i++)
1.20 nicm 317: if (capcmp((PredIdx) i, t1->Strings[i], t2->Strings[i]))
1.8 millert 318: return (FALSE);
1.1 millert 319:
1.8 millert 320: return (TRUE);
1.1 millert 321: }
322:
323: #define TIC_EXPAND(result) _nc_tic_expand(result, outform==F_TERMINFO, numbers)
324:
1.8 millert 325: static void
1.20 nicm 326: print_uses(ENTRY * ep, FILE *fp)
1.9 millert 327: /* print an entry's use references */
328: {
1.24 ! nicm 329: if (!ep->nuses) {
! 330: fputs("NULL", fp);
! 331: } else {
! 332: unsigned i;
1.9 millert 333:
334: for (i = 0; i < ep->nuses; i++) {
335: fputs(ep->uses[i].name, fp);
336: if (i < ep->nuses - 1)
337: fputs(" ", fp);
338: }
1.24 ! nicm 339: }
1.9 millert 340: }
341:
1.10 millert 342: static const char *
1.9 millert 343: dump_boolean(int val)
344: /* display the value of a boolean capability */
345: {
346: switch (val) {
347: case ABSENT_BOOLEAN:
348: return (s_absent);
349: case CANCELLED_BOOLEAN:
350: return (s_cancel);
351: case FALSE:
352: return ("F");
353: case TRUE:
354: return ("T");
355: default:
356: return ("?");
357: }
358: }
359:
360: static void
1.24 ! nicm 361: dump_numeric(int val, char *buf)
! 362: /* display the value of a numeric capability */
1.9 millert 363: {
364: switch (val) {
365: case ABSENT_NUMERIC:
1.24 ! nicm 366: _nc_STRCPY(buf, s_absent, MAX_STRING);
1.9 millert 367: break;
368: case CANCELLED_NUMERIC:
1.24 ! nicm 369: _nc_STRCPY(buf, s_cancel, MAX_STRING);
1.9 millert 370: break;
371: default:
1.24 ! nicm 372: _nc_SPRINTF(buf, _nc_SLIMIT(MAX_STRING) "%d", val);
1.9 millert 373: break;
374: }
375: }
376:
377: static void
1.24 ! nicm 378: dump_string(char *val, char *buf)
1.9 millert 379: /* display the value of a string capability */
380: {
381: if (val == ABSENT_STRING)
1.24 ! nicm 382: _nc_STRCPY(buf, s_absent, MAX_STRING);
1.9 millert 383: else if (val == CANCELLED_STRING)
1.24 ! nicm 384: _nc_STRCPY(buf, s_cancel, MAX_STRING);
1.9 millert 385: else {
1.24 ! nicm 386: _nc_SPRINTF(buf, _nc_SLIMIT(MAX_STRING)
! 387: "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val));
1.9 millert 388: }
389: }
390:
1.24 ! nicm 391: /*
! 392: * Show "comparing..." message for the given terminal names.
! 393: */
! 394: static void
! 395: show_comparing(char **names)
! 396: {
! 397: if (itrace) {
! 398: switch (compare) {
! 399: case C_DIFFERENCE:
! 400: (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname);
! 401: break;
! 402:
! 403: case C_COMMON:
! 404: (void) fprintf(stderr, "%s: dumping common capabilities\n", _nc_progname);
! 405: break;
! 406:
! 407: case C_NAND:
! 408: (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname);
! 409: break;
! 410: }
! 411: }
! 412: if (*names) {
! 413: printf("comparing %s", *names++);
! 414: if (*names) {
! 415: printf(" to %s", *names++);
! 416: while (*names) {
! 417: printf(", %s", *names++);
! 418: }
! 419: }
! 420: printf(".\n");
! 421: }
! 422: }
! 423:
! 424: /*
! 425: * ncurses stores two types of non-standard capabilities:
! 426: * a) capabilities listed past the "STOP-HERE" comment in the Caps file.
! 427: * These are used in the terminfo source file to provide data for termcaps,
! 428: * e.g., when there is no equivalent capability in terminfo, as well as for
! 429: * widely-used non-standard capabilities.
! 430: * b) user-definable capabilities, via "tic -x".
! 431: *
! 432: * However, if "-x" is omitted from the tic command, both types of
! 433: * non-standard capability are not loaded into the terminfo database. This
! 434: * macro is used for limit-checks against the symbols that tic uses to omit
! 435: * the two types of non-standard entry.
! 436: */
! 437: #if NCURSES_XNAMES
! 438: #define check_user_definable(n,limit) if (!_nc_user_definable && (n) > (limit)) break
! 439: #else
! 440: #define check_user_definable(n,limit) if ((n) > (limit)) break
! 441: #endif
! 442:
! 443: /*
! 444: * Use these macros to simplify loops on C_COMMON and C_NAND:
! 445: */
! 446: #define for_each_entry() while (entries[extra].tterm.term_names)
! 447: #define next_entry (&(entries[extra++].tterm))
! 448:
1.9 millert 449: static void
1.20 nicm 450: compare_predicate(PredType type, PredIdx idx, const char *name)
1.1 millert 451: /* predicate function to use for entry difference reports */
452: {
1.15 mpech 453: ENTRY *e1 = &entries[0];
454: ENTRY *e2 = &entries[1];
1.24 ! nicm 455: char buf1[MAX_STRING];
! 456: char buf2[MAX_STRING];
1.9 millert 457: int b1, b2;
458: int n1, n2;
1.8 millert 459: char *s1, *s2;
1.24 ! nicm 460: bool found;
! 461: int extra = 1;
1.8 millert 462:
463: switch (type) {
1.9 millert 464: case CMP_BOOLEAN:
1.24 ! nicm 465: check_user_definable(idx, BOOLWRITE);
1.9 millert 466: b1 = e1->tterm.Booleans[idx];
1.8 millert 467: switch (compare) {
468: case C_DIFFERENCE:
1.24 ! nicm 469: b2 = next_entry->Booleans[idx];
! 470: if (!(no_boolean(b1) && no_boolean(b2)) && (b1 != b2))
1.9 millert 471: (void) printf("\t%s: %s%s%s.\n",
1.11 millert 472: name,
473: dump_boolean(b1),
474: bool_sep,
475: dump_boolean(b2));
1.8 millert 476: break;
477:
478: case C_COMMON:
1.24 ! nicm 479: if (b1 != ABSENT_BOOLEAN) {
! 480: found = TRUE;
! 481: for_each_entry() {
! 482: b2 = next_entry->Booleans[idx];
! 483: if (b1 != b2) {
! 484: found = FALSE;
! 485: break;
! 486: }
! 487: }
! 488: if (found) {
! 489: (void) printf("\t%s= %s.\n", name, dump_boolean(b1));
! 490: }
! 491: }
1.8 millert 492: break;
493:
494: case C_NAND:
1.24 ! nicm 495: if (b1 == ABSENT_BOOLEAN) {
! 496: found = TRUE;
! 497: for_each_entry() {
! 498: b2 = next_entry->Booleans[idx];
! 499: if (b1 != b2) {
! 500: found = FALSE;
! 501: break;
! 502: }
! 503: }
! 504: if (found) {
! 505: (void) printf("\t!%s.\n", name);
! 506: }
! 507: }
1.8 millert 508: break;
509: }
510: break;
1.1 millert 511:
1.9 millert 512: case CMP_NUMBER:
1.24 ! nicm 513: check_user_definable(idx, NUMWRITE);
1.9 millert 514: n1 = e1->tterm.Numbers[idx];
1.8 millert 515: switch (compare) {
516: case C_DIFFERENCE:
1.24 ! nicm 517: n2 = next_entry->Numbers[idx];
! 518: if (!(no_numeric(n1) && no_numeric(n2)) && n1 != n2) {
! 519: dump_numeric(n1, buf1);
! 520: dump_numeric(n2, buf2);
1.9 millert 521: (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
1.24 ! nicm 522: }
1.8 millert 523: break;
1.1 millert 524:
1.8 millert 525: case C_COMMON:
1.24 ! nicm 526: if (n1 != ABSENT_NUMERIC) {
! 527: found = TRUE;
! 528: for_each_entry() {
! 529: n2 = next_entry->Numbers[idx];
! 530: if (n1 != n2) {
! 531: found = FALSE;
! 532: break;
! 533: }
! 534: }
! 535: if (found) {
! 536: dump_numeric(n1, buf1);
! 537: (void) printf("\t%s= %s.\n", name, buf1);
! 538: }
! 539: }
1.8 millert 540: break;
1.1 millert 541:
1.8 millert 542: case C_NAND:
1.24 ! nicm 543: if (n1 == ABSENT_NUMERIC) {
! 544: found = TRUE;
! 545: for_each_entry() {
! 546: n2 = next_entry->Numbers[idx];
! 547: if (n1 != n2) {
! 548: found = FALSE;
! 549: break;
! 550: }
! 551: }
! 552: if (found) {
! 553: (void) printf("\t!%s.\n", name);
! 554: }
! 555: }
1.8 millert 556: break;
557: }
558: break;
1.1 millert 559:
1.9 millert 560: case CMP_STRING:
1.24 ! nicm 561: check_user_definable(idx, STRWRITE);
1.9 millert 562: s1 = e1->tterm.Strings[idx];
1.8 millert 563: switch (compare) {
564: case C_DIFFERENCE:
1.24 ! nicm 565: s2 = next_entry->Strings[idx];
! 566: if (!(no_string(s1) && no_string(s2)) && capcmp(idx, s1, s2)) {
! 567: dump_string(s1, buf1);
! 568: dump_string(s2, buf2);
1.8 millert 569: if (strcmp(buf1, buf2))
1.9 millert 570: (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
1.8 millert 571: }
572: break;
1.1 millert 573:
1.8 millert 574: case C_COMMON:
1.24 ! nicm 575: if (s1 != ABSENT_STRING) {
! 576: found = TRUE;
! 577: for_each_entry() {
! 578: s2 = next_entry->Strings[idx];
! 579: if (capcmp(idx, s1, s2) != 0) {
! 580: found = FALSE;
! 581: break;
! 582: }
! 583: }
! 584: if (found) {
! 585: (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1));
! 586: }
! 587: }
1.8 millert 588: break;
1.1 millert 589:
1.8 millert 590: case C_NAND:
1.24 ! nicm 591: if (s1 == ABSENT_STRING) {
! 592: found = TRUE;
! 593: for_each_entry() {
! 594: s2 = next_entry->Strings[idx];
! 595: if (s2 != s1) {
! 596: found = FALSE;
! 597: break;
! 598: }
! 599: }
! 600: if (found) {
! 601: (void) printf("\t!%s.\n", name);
! 602: }
! 603: }
1.8 millert 604: break;
1.1 millert 605: }
1.8 millert 606: break;
1.9 millert 607:
608: case CMP_USE:
609: /* unlike the other modes, this compares *all* use entries */
610: switch (compare) {
611: case C_DIFFERENCE:
612: if (!useeq(e1, e2)) {
613: (void) fputs("\tuse: ", stdout);
614: print_uses(e1, stdout);
615: fputs(", ", stdout);
616: print_uses(e2, stdout);
617: fputs(".\n", stdout);
618: }
619: break;
620:
621: case C_COMMON:
1.24 ! nicm 622: if (e1->nuses) {
! 623: found = TRUE;
! 624: for_each_entry() {
! 625: e2 = &entries[extra++];
! 626: if (e2->nuses != e1->nuses || !useeq(e1, e2)) {
! 627: found = FALSE;
! 628: break;
! 629: }
! 630: }
! 631: if (found) {
! 632: (void) fputs("\tuse: ", stdout);
! 633: print_uses(e1, stdout);
! 634: fputs(".\n", stdout);
! 635: }
1.9 millert 636: }
637: break;
638:
639: case C_NAND:
1.24 ! nicm 640: if (!e1->nuses) {
! 641: found = TRUE;
! 642: for_each_entry() {
! 643: e2 = &entries[extra++];
! 644: if (e2->nuses != e1->nuses) {
! 645: found = FALSE;
! 646: break;
! 647: }
! 648: }
! 649: if (found) {
! 650: (void) printf("\t!use.\n");
! 651: }
! 652: }
1.9 millert 653: break;
654: }
1.8 millert 655: }
1.1 millert 656: }
657:
658: /***************************************************************************
659: *
660: * Init string analysis
661: *
662: ***************************************************************************/
663:
1.24 ! nicm 664: #define DATA(from, to) { { from }, { to } }
! 665: #define DATAX() DATA("", "")
! 666:
1.8 millert 667: typedef struct {
1.24 ! nicm 668: const char from[4];
! 669: const char to[12];
1.8 millert 670: } assoc;
1.1 millert 671:
672: static const assoc std_caps[] =
673: {
674: /* these are specified by X.364 and iBCS2 */
1.24 ! nicm 675: DATA("\033c", "RIS"), /* full reset */
! 676: DATA("\0337", "SC"), /* save cursor */
! 677: DATA("\0338", "RC"), /* restore cursor */
! 678: DATA("\033[r", "RSR"), /* not an X.364 mnemonic */
! 679: DATA("\033[m", "SGR0"), /* not an X.364 mnemonic */
! 680: DATA("\033[2J", "ED2"), /* clear page */
1.1 millert 681:
682: /* this group is specified by ISO 2022 */
1.24 ! nicm 683: DATA("\033(0", "ISO DEC G0"), /* enable DEC graphics for G0 */
! 684: DATA("\033(A", "ISO UK G0"), /* enable UK chars for G0 */
! 685: DATA("\033(B", "ISO US G0"), /* enable US chars for G0 */
! 686: DATA("\033)0", "ISO DEC G1"), /* enable DEC graphics for G1 */
! 687: DATA("\033)A", "ISO UK G1"), /* enable UK chars for G1 */
! 688: DATA("\033)B", "ISO US G1"), /* enable US chars for G1 */
1.1 millert 689:
1.20 nicm 690: /* these are DEC private controls widely supported by emulators */
1.24 ! nicm 691: DATA("\033=", "DECPAM"), /* application keypad mode */
! 692: DATA("\033>", "DECPNM"), /* normal keypad mode */
! 693: DATA("\033<", "DECANSI"), /* enter ANSI mode */
! 694: DATA("\033[!p", "DECSTR"), /* soft reset */
! 695: DATA("\033 F", "S7C1T"), /* 7-bit controls */
1.1 millert 696:
1.24 ! nicm 697: DATAX()
1.1 millert 698: };
699:
1.20 nicm 700: static const assoc std_modes[] =
701: /* ECMA \E[ ... [hl] modes recognized by many emulators */
702: {
1.24 ! nicm 703: DATA("2", "AM"), /* keyboard action mode */
! 704: DATA("4", "IRM"), /* insert/replace mode */
! 705: DATA("12", "SRM"), /* send/receive mode */
! 706: DATA("20", "LNM"), /* linefeed mode */
! 707: DATAX()
1.20 nicm 708: };
709:
1.1 millert 710: static const assoc private_modes[] =
711: /* DEC \E[ ... [hl] modes recognized by many emulators */
712: {
1.24 ! nicm 713: DATA("1", "CKM"), /* application cursor keys */
! 714: DATA("2", "ANM"), /* set VT52 mode */
! 715: DATA("3", "COLM"), /* 132-column mode */
! 716: DATA("4", "SCLM"), /* smooth scroll */
! 717: DATA("5", "SCNM"), /* reverse video mode */
! 718: DATA("6", "OM"), /* origin mode */
! 719: DATA("7", "AWM"), /* wraparound mode */
! 720: DATA("8", "ARM"), /* auto-repeat mode */
! 721: DATAX()
1.1 millert 722: };
723:
724: static const assoc ecma_highlights[] =
725: /* recognize ECMA attribute sequences */
726: {
1.24 ! nicm 727: DATA("0", "NORMAL"), /* normal */
! 728: DATA("1", "+BOLD"), /* bold on */
! 729: DATA("2", "+DIM"), /* dim on */
! 730: DATA("3", "+ITALIC"), /* italic on */
! 731: DATA("4", "+UNDERLINE"), /* underline on */
! 732: DATA("5", "+BLINK"), /* blink on */
! 733: DATA("6", "+FASTBLINK"), /* fastblink on */
! 734: DATA("7", "+REVERSE"), /* reverse on */
! 735: DATA("8", "+INVISIBLE"), /* invisible on */
! 736: DATA("9", "+DELETED"), /* deleted on */
! 737: DATA("10", "MAIN-FONT"), /* select primary font */
! 738: DATA("11", "ALT-FONT-1"), /* select alternate font 1 */
! 739: DATA("12", "ALT-FONT-2"), /* select alternate font 2 */
! 740: DATA("13", "ALT-FONT-3"), /* select alternate font 3 */
! 741: DATA("14", "ALT-FONT-4"), /* select alternate font 4 */
! 742: DATA("15", "ALT-FONT-5"), /* select alternate font 5 */
! 743: DATA("16", "ALT-FONT-6"), /* select alternate font 6 */
! 744: DATA("17", "ALT-FONT-7"), /* select alternate font 7 */
! 745: DATA("18", "ALT-FONT-1"), /* select alternate font 1 */
! 746: DATA("19", "ALT-FONT-1"), /* select alternate font 1 */
! 747: DATA("20", "FRAKTUR"), /* Fraktur font */
! 748: DATA("21", "DOUBLEUNDER"), /* double underline */
! 749: DATA("22", "-DIM"), /* dim off */
! 750: DATA("23", "-ITALIC"), /* italic off */
! 751: DATA("24", "-UNDERLINE"), /* underline off */
! 752: DATA("25", "-BLINK"), /* blink off */
! 753: DATA("26", "-FASTBLINK"), /* fastblink off */
! 754: DATA("27", "-REVERSE"), /* reverse off */
! 755: DATA("28", "-INVISIBLE"), /* invisible off */
! 756: DATA("29", "-DELETED"), /* deleted off */
! 757: DATAX()
1.1 millert 758: };
759:
1.24 ! nicm 760: #undef DATA
! 761:
1.20 nicm 762: static int
763: skip_csi(const char *cap)
764: {
765: int result = 0;
766: if (cap[0] == '\033' && cap[1] == '[')
767: result = 2;
768: else if (UChar(cap[0]) == 0233)
769: result = 1;
770: return result;
771: }
772:
773: static bool
1.24 ! nicm 774: same_param(const char *table, const char *param, size_t length)
1.20 nicm 775: {
776: bool result = FALSE;
777: if (strncmp(table, param, length) == 0) {
778: result = !isdigit(UChar(param[length]));
779: }
780: return result;
781: }
782:
783: static char *
1.24 ! nicm 784: lookup_params(const assoc * table, char *dst, char *src)
1.20 nicm 785: {
786: char *result = 0;
787: const char *ep = strtok(src, ";");
788:
789: if (ep != 0) {
790: const assoc *ap;
791:
792: do {
793: bool found = FALSE;
794:
1.24 ! nicm 795: for (ap = table; ap->from[0]; ap++) {
1.20 nicm 796: size_t tlen = strlen(ap->from);
797:
798: if (same_param(ap->from, ep, tlen)) {
1.24 ! nicm 799: _nc_STRCAT(dst, ap->to, MAX_TERMINFO_LENGTH);
1.20 nicm 800: found = TRUE;
801: break;
802: }
803: }
804:
805: if (!found)
1.24 ! nicm 806: _nc_STRCAT(dst, ep, MAX_TERMINFO_LENGTH);
! 807: _nc_STRCAT(dst, ";", MAX_TERMINFO_LENGTH);
1.20 nicm 808: } while
809: ((ep = strtok((char *) 0, ";")));
810:
1.24 ! nicm 811: dst[strlen(dst) - 1] = '\0';
1.20 nicm 812:
813: result = dst;
814: }
815: return result;
816: }
817:
1.8 millert 818: static void
1.24 ! nicm 819: analyze_string(const char *name, const char *cap, TERMTYPE2 *tp)
1.1 millert 820: {
1.8 millert 821: char buf2[MAX_TERMINFO_LENGTH];
1.20 nicm 822: const char *sp;
1.8 millert 823: const assoc *ap;
1.20 nicm 824: int tp_lines = tp->Numbers[2];
1.1 millert 825:
1.24 ! nicm 826: if (!VALID_STRING(cap))
1.1 millert 827: return;
828: (void) printf("%s: ", name);
829:
1.8 millert 830: for (sp = cap; *sp; sp++) {
831: int i;
1.20 nicm 832: int csi;
1.8 millert 833: size_t len = 0;
1.20 nicm 834: size_t next;
1.1 millert 835: const char *expansion = 0;
1.20 nicm 836: char buf3[MAX_TERMINFO_LENGTH];
1.1 millert 837:
838: /* first, check other capabilities in this entry */
1.8 millert 839: for (i = 0; i < STRCOUNT; i++) {
840: char *cp = tp->Strings[i];
1.1 millert 841:
1.24 ! nicm 842: /* don't use function-key capabilities */
! 843: if (strnames[i] == NULL)
! 844: continue;
1.23 krw 845: if (strnames[i][0] == 'k' && strnames[i][1] == 'f')
1.1 millert 846: continue;
847:
1.24 ! nicm 848: if (VALID_STRING(cp) &&
! 849: cp[0] != '\0' &&
! 850: cp != cap) {
1.1 millert 851: len = strlen(cp);
1.24 ! nicm 852: _nc_STRNCPY(buf2, sp, len);
1.1 millert 853: buf2[len] = '\0';
854:
855: if (_nc_capcmp(cp, buf2))
856: continue;
857:
1.24 ! nicm 858: #define ISRS(s) (!strncmp((s), "is", (size_t) 2) || !strncmp((s), "rs", (size_t) 2))
1.1 millert 859: /*
860: * Theoretically we just passed the test for translation
861: * (equality once the padding is stripped). However, there
862: * are a few more hoops that need to be jumped so that
863: * identical pairs of initialization and reset strings
864: * don't just refer to each other.
865: */
866: if (ISRS(name) || ISRS(strnames[i]))
867: if (cap < cp)
868: continue;
869: #undef ISRS
870:
871: expansion = strnames[i];
872: break;
873: }
874: }
875:
876: /* now check the standard capabilities */
1.20 nicm 877: if (!expansion) {
878: csi = skip_csi(sp);
1.24 ! nicm 879: for (ap = std_caps; ap->from[0]; ap++) {
1.20 nicm 880: size_t adj = (size_t) (csi ? 2 : 0);
881:
1.1 millert 882: len = strlen(ap->from);
1.20 nicm 883: if (csi && skip_csi(ap->from) != csi)
884: continue;
885: if (len > adj
886: && strncmp(ap->from + adj, sp + csi, len - adj) == 0) {
1.1 millert 887: expansion = ap->to;
1.20 nicm 888: len -= adj;
889: len += (size_t) csi;
1.1 millert 890: break;
891: }
892: }
1.20 nicm 893: }
894:
895: /* now check for standard-mode sequences */
896: if (!expansion
897: && (csi = skip_csi(sp)) != 0
1.24 ! nicm 898: && (len = (strspn) (sp + csi, "0123456789;"))
1.20 nicm 899: && (len < sizeof(buf3))
900: && (next = (size_t) csi + len)
901: && ((sp[next] == 'h') || (sp[next] == 'l'))) {
902:
1.24 ! nicm 903: _nc_STRCPY(buf2,
! 904: ((sp[next] == 'h')
! 905: ? "ECMA+"
! 906: : "ECMA-"),
! 907: sizeof(buf2));
! 908: _nc_STRNCPY(buf3, sp + csi, len);
1.20 nicm 909: buf3[len] = '\0';
910:
1.24 ! nicm 911: expansion = lookup_params(std_modes, buf2, buf3);
1.20 nicm 912: }
1.1 millert 913:
914: /* now check for private-mode sequences */
915: if (!expansion
1.20 nicm 916: && (csi = skip_csi(sp)) != 0
917: && sp[csi] == '?'
1.24 ! nicm 918: && (len = (strspn) (sp + csi + 1, "0123456789;"))
1.20 nicm 919: && (len < sizeof(buf3))
920: && (next = (size_t) csi + 1 + len)
921: && ((sp[next] == 'h') || (sp[next] == 'l'))) {
1.1 millert 922:
1.24 ! nicm 923: _nc_STRCPY(buf2,
! 924: ((sp[next] == 'h')
! 925: ? "DEC+"
! 926: : "DEC-"),
! 927: sizeof(buf2));
! 928: _nc_STRNCPY(buf3, sp + csi + 1, len);
1.1 millert 929: buf3[len] = '\0';
930:
1.24 ! nicm 931: expansion = lookup_params(private_modes, buf2, buf3);
1.1 millert 932: }
933:
934: /* now check for ECMA highlight sequences */
935: if (!expansion
1.20 nicm 936: && (csi = skip_csi(sp)) != 0
1.24 ! nicm 937: && (len = (strspn) (sp + csi, "0123456789;")) != 0
1.20 nicm 938: && (len < sizeof(buf3))
939: && (next = (size_t) csi + len)
940: && sp[next] == 'm') {
1.1 millert 941:
1.24 ! nicm 942: _nc_STRCPY(buf2, "SGR:", sizeof(buf2));
! 943: _nc_STRNCPY(buf3, sp + csi, len);
1.1 millert 944: buf3[len] = '\0';
1.20 nicm 945: len += (size_t) csi + 1;
1.1 millert 946:
1.24 ! nicm 947: expansion = lookup_params(ecma_highlights, buf2, buf3);
1.20 nicm 948: }
1.1 millert 949:
1.20 nicm 950: if (!expansion
951: && (csi = skip_csi(sp)) != 0
952: && sp[csi] == 'm') {
953: len = (size_t) csi + 1;
1.24 ! nicm 954: _nc_STRCPY(buf2, "SGR:", sizeof(buf2));
! 955: _nc_STRCAT(buf2, ecma_highlights[0].to, sizeof(buf2));
1.1 millert 956: expansion = buf2;
957: }
1.20 nicm 958:
1.1 millert 959: /* now check for scroll region reset */
1.20 nicm 960: if (!expansion
961: && (csi = skip_csi(sp)) != 0) {
962: if (sp[csi] == 'r') {
1.1 millert 963: expansion = "RSR";
1.20 nicm 964: len = 1;
965: } else {
1.24 ! nicm 966: _nc_SPRINTF(buf2, _nc_SLIMIT(sizeof(buf2)) "1;%dr", tp_lines);
1.20 nicm 967: len = strlen(buf2);
968: if (strncmp(buf2, sp + csi, len) == 0)
969: expansion = "RSR";
970: }
971: len += (size_t) csi;
1.1 millert 972: }
973:
974: /* now check for home-down */
1.20 nicm 975: if (!expansion
976: && (csi = skip_csi(sp)) != 0) {
1.24 ! nicm 977: _nc_SPRINTF(buf2, _nc_SLIMIT(sizeof(buf2)) "%d;1H", tp_lines);
1.1 millert 978: len = strlen(buf2);
1.20 nicm 979: if (strncmp(buf2, sp + csi, len) == 0) {
1.8 millert 980: expansion = "LL";
1.20 nicm 981: } else {
1.24 ! nicm 982: _nc_SPRINTF(buf2, _nc_SLIMIT(sizeof(buf2)) "%dH", tp_lines);
1.20 nicm 983: len = strlen(buf2);
984: if (strncmp(buf2, sp + csi, len) == 0) {
985: expansion = "LL";
986: }
987: }
988: len += (size_t) csi;
1.1 millert 989: }
990:
991: /* now look at the expansion we got, if any */
1.8 millert 992: if (expansion) {
1.20 nicm 993: printf("{%s}", expansion);
1.1 millert 994: sp += len - 1;
1.8 millert 995: } else {
1.1 millert 996: /* couldn't match anything */
997: buf2[0] = *sp;
998: buf2[1] = '\0';
1.20 nicm 999: fputs(TIC_EXPAND(buf2), stdout);
1.1 millert 1000: }
1001: }
1.20 nicm 1002: putchar('\n');
1.1 millert 1003: }
1004:
1005: /***************************************************************************
1006: *
1007: * File comparison
1008: *
1009: ***************************************************************************/
1010:
1.8 millert 1011: static void
1012: file_comparison(int argc, char *argv[])
1.1 millert 1013: {
1014: #define MAXCOMPARE 2
1015: /* someday we may allow comparisons on more files */
1.8 millert 1016: int filecount = 0;
1017: ENTRY *heads[MAXCOMPARE];
1018: ENTRY *qp, *rp;
1019: int i, n;
1.1 millert 1020:
1.20 nicm 1021: memset(heads, 0, sizeof(heads));
1.24 ! nicm 1022: dump_init((char *) 0, F_LITERAL, S_TERMINFO,
! 1023: FALSE, 0, 65535, itrace, FALSE, FALSE, FALSE);
1.1 millert 1024:
1.8 millert 1025: for (n = 0; n < argc && n < MAXCOMPARE; n++) {
1.9 millert 1026: if (freopen(argv[n], "r", stdin) == 0)
1.1 millert 1027: _nc_err_abort("Can't open %s", argv[n]);
1028:
1.24 ! nicm 1029: #if NO_LEAKS
! 1030: entered[n].head = _nc_head;
! 1031: entered[n].tail = _nc_tail;
! 1032: #endif
1.9 millert 1033: _nc_head = _nc_tail = 0;
1.1 millert 1034:
1035: /* parse entries out of the source file */
1036: _nc_set_source(argv[n]);
1.20 nicm 1037: _nc_read_entry_source(stdin, NULL, TRUE, literal, NULLHOOK);
1.1 millert 1038:
1039: if (itrace)
1.8 millert 1040: (void) fprintf(stderr, "Resolving file %d...\n", n - 0);
1.1 millert 1041:
1.9 millert 1042: /* maybe do use resolution */
1.20 nicm 1043: if (!_nc_resolve_uses2(!limited, literal)) {
1.1 millert 1044: (void) fprintf(stderr,
1.11 millert 1045: "There are unresolved use entries in %s:\n",
1046: argv[n]);
1.9 millert 1047: for_entry_list(qp) {
1.8 millert 1048: if (qp->nuses) {
1.9 millert 1049: (void) fputs(qp->tterm.term_names, stderr);
1050: (void) fputc('\n', stderr);
1051: }
1.8 millert 1052: }
1.20 nicm 1053: ExitProgram(EXIT_FAILURE);
1.1 millert 1054: }
1055:
1056: heads[filecount] = _nc_head;
1057: filecount++;
1058: }
1059:
1060: /* OK, all entries are in core. Ready to do the comparison */
1061: if (itrace)
1062: (void) fprintf(stderr, "Entries are now in core...\n");
1063:
1.9 millert 1064: /* The entry-matching loop. Sigh, this is intrinsically quadratic. */
1.8 millert 1065: for (qp = heads[0]; qp; qp = qp->next) {
1.1 millert 1066: for (rp = heads[1]; rp; rp = rp->next)
1.8 millert 1067: if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
1.9 millert 1068: if (qp->ncrosslinks < MAX_CROSSLINKS)
1069: qp->crosslinks[qp->ncrosslinks] = rp;
1070: qp->ncrosslinks++;
1071:
1072: if (rp->ncrosslinks < MAX_CROSSLINKS)
1073: rp->crosslinks[rp->ncrosslinks] = qp;
1074: rp->ncrosslinks++;
1.1 millert 1075: }
1076: }
1077:
1078: /* now we have two circular lists with crosslinks */
1079: if (itrace)
1080: (void) fprintf(stderr, "Name matches are done...\n");
1081:
1.9 millert 1082: for (qp = heads[0]; qp; qp = qp->next) {
1083: if (qp->ncrosslinks > 1) {
1.1 millert 1084: (void) fprintf(stderr,
1.11 millert 1085: "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
1086: _nc_first_name(qp->tterm.term_names),
1087: argv[0],
1088: qp->ncrosslinks,
1089: argv[1]);
1.9 millert 1090: for (i = 0; i < qp->ncrosslinks; i++)
1.1 millert 1091: (void) fprintf(stderr,
1.11 millert 1092: "\t%s\n",
1093: _nc_first_name((qp->crosslinks[i])->tterm.term_names));
1.1 millert 1094: }
1.9 millert 1095: }
1096:
1097: for (rp = heads[1]; rp; rp = rp->next) {
1098: if (rp->ncrosslinks > 1) {
1.1 millert 1099: (void) fprintf(stderr,
1.11 millert 1100: "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
1101: _nc_first_name(rp->tterm.term_names),
1102: argv[1],
1103: rp->ncrosslinks,
1104: argv[0]);
1.9 millert 1105: for (i = 0; i < rp->ncrosslinks; i++)
1.1 millert 1106: (void) fprintf(stderr,
1.11 millert 1107: "\t%s\n",
1108: _nc_first_name((rp->crosslinks[i])->tterm.term_names));
1.1 millert 1109: }
1.9 millert 1110: }
1.1 millert 1111:
1112: (void) printf("In file 1 (%s) only:\n", argv[0]);
1113: for (qp = heads[0]; qp; qp = qp->next)
1.9 millert 1114: if (qp->ncrosslinks == 0)
1.1 millert 1115: (void) printf("\t%s\n",
1.11 millert 1116: _nc_first_name(qp->tterm.term_names));
1.1 millert 1117:
1118: (void) printf("In file 2 (%s) only:\n", argv[1]);
1119: for (rp = heads[1]; rp; rp = rp->next)
1.9 millert 1120: if (rp->ncrosslinks == 0)
1.1 millert 1121: (void) printf("\t%s\n",
1.11 millert 1122: _nc_first_name(rp->tterm.term_names));
1.1 millert 1123:
1124: (void) printf("The following entries are equivalent:\n");
1.8 millert 1125: for (qp = heads[0]; qp; qp = qp->next) {
1.9 millert 1126: if (qp->ncrosslinks == 1) {
1127: rp = qp->crosslinks[0];
1.1 millert 1128:
1.9 millert 1129: repair_acsc(&qp->tterm);
1130: repair_acsc(&rp->tterm);
1131: #if NCURSES_XNAMES
1132: _nc_align_termtype(&qp->tterm, &rp->tterm);
1133: #endif
1134: if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) {
1135: char name1[NAMESIZE], name2[NAMESIZE];
1.1 millert 1136:
1.24 ! nicm 1137: canonical_name(qp->tterm.term_names, name1);
! 1138: canonical_name(rp->tterm.term_names, name2);
1.1 millert 1139:
1.9 millert 1140: (void) printf("%s = %s\n", name1, name2);
1141: }
1.1 millert 1142: }
1143: }
1144:
1145: (void) printf("Differing entries:\n");
1146: termcount = 2;
1.8 millert 1147: for (qp = heads[0]; qp; qp = qp->next) {
1.1 millert 1148:
1.9 millert 1149: if (qp->ncrosslinks == 1) {
1150: rp = qp->crosslinks[0];
1.2 millert 1151: #if NCURSES_XNAMES
1.9 millert 1152: /* sorry - we have to do this on each pass */
1.2 millert 1153: _nc_align_termtype(&qp->tterm, &rp->tterm);
1154: #endif
1.9 millert 1155: if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) {
1156: char name1[NAMESIZE], name2[NAMESIZE];
1.24 ! nicm 1157: char *names[3];
! 1158:
! 1159: names[0] = name1;
! 1160: names[1] = name2;
! 1161: names[2] = 0;
1.1 millert 1162:
1.9 millert 1163: entries[0] = *qp;
1164: entries[1] = *rp;
1.1 millert 1165:
1.24 ! nicm 1166: canonical_name(qp->tterm.term_names, name1);
! 1167: canonical_name(rp->tterm.term_names, name2);
1.1 millert 1168:
1.9 millert 1169: switch (compare) {
1170: case C_DIFFERENCE:
1.24 ! nicm 1171: show_comparing(names);
1.9 millert 1172: compare_entry(compare_predicate, &entries->tterm, quiet);
1173: break;
1.1 millert 1174:
1.9 millert 1175: case C_COMMON:
1.24 ! nicm 1176: show_comparing(names);
1.9 millert 1177: compare_entry(compare_predicate, &entries->tterm, quiet);
1178: break;
1.1 millert 1179:
1.9 millert 1180: case C_NAND:
1.24 ! nicm 1181: show_comparing(names);
1.9 millert 1182: compare_entry(compare_predicate, &entries->tterm, quiet);
1183: break;
1.1 millert 1184:
1.9 millert 1185: }
1.1 millert 1186: }
1187: }
1188: }
1189: }
1190:
1.8 millert 1191: static void
1192: usage(void)
1.1 millert 1193: {
1.24 ! nicm 1194: #define DATA(s) s "\n"
! 1195: static const char head[] =
1.8 millert 1196: {
1.24 ! nicm 1197: DATA("Usage: infocmp [options] [-A directory] [-B directory] [termname...]")
! 1198: DATA("")
! 1199: DATA("Options:")
! 1200: };
! 1201: #undef DATA
! 1202: /* length is given here so the compiler can make everything readonly */
! 1203: #define DATA(s) s
! 1204: static const char options[][46] =
! 1205: {
! 1206: " -0 print single-row"
1.8 millert 1207: ," -1 print single-column"
1208: ," -C use termcap-names"
1.24 ! nicm 1209: ," -D print database locations"
! 1210: ," -E format output as C tables"
1.8 millert 1211: ," -F compare terminfo-files"
1.24 ! nicm 1212: ," -G format %{number} to %'char'"
1.8 millert 1213: ," -I use terminfo-names"
1.24 ! nicm 1214: ," -K use termcap-names and BSD syntax"
1.8 millert 1215: ," -L use long names"
1216: ," -R subset (see manpage)"
1217: ," -T eliminate size limits (test)"
1.24 ! nicm 1218: ," -U do not post-process entries"
1.8 millert 1219: ," -V print version"
1.24 ! nicm 1220: ," -W wrap long strings per -w[n]"
1.10 millert 1221: #if NCURSES_XNAMES
1222: ," -a with -F, list commented-out caps"
1223: #endif
1.8 millert 1224: ," -c list common capabilities"
1225: ," -d list different capabilities"
1226: ," -e format output for C initializer"
1227: ," -f with -1, format complex strings"
1228: ," -g format %'char' to %{number}"
1229: ," -i analyze initialization/reset"
1230: ," -l output terminfo names"
1231: ," -n list capabilities in neither"
1232: ," -p ignore padding specifiers"
1.24 ! nicm 1233: ," -Q number dump compiled description"
1.9 millert 1234: ," -q brief listing, removes headers"
1.8 millert 1235: ," -r with -C, output in termcap form"
1.9 millert 1236: ," -r with -F, resolve use-references"
1.8 millert 1237: ," -s [d|i|l|c] sort fields"
1.20 nicm 1238: #if NCURSES_XNAMES
1239: ," -t suppress commented-out capabilities"
1240: #endif
1.8 millert 1241: ," -u produce source with 'use='"
1242: ," -v number (verbose)"
1243: ," -w number (width)"
1.20 nicm 1244: #if NCURSES_XNAMES
1.24 ! nicm 1245: ," -x unknown capabilities are user-defined"
1.20 nicm 1246: #endif
1.8 millert 1247: };
1.24 ! nicm 1248: #undef DATA
! 1249: const size_t last = SIZEOF(options);
! 1250: const size_t left = (last + 1) / 2;
1.8 millert 1251: size_t n;
1252:
1.24 ! nicm 1253: fputs(head, stderr);
1.8 millert 1254: for (n = 0; n < left; n++) {
1.24 ! nicm 1255: size_t m = n + left;
1.8 millert 1256: if (m < last)
1.24 ! nicm 1257: fprintf(stderr, "%-40.40s%s\n", options[n], options[m]);
1.8 millert 1258: else
1.24 ! nicm 1259: fprintf(stderr, "%s\n", options[n]);
1.8 millert 1260: }
1.20 nicm 1261: ExitProgram(EXIT_FAILURE);
1.1 millert 1262: }
1263:
1.8 millert 1264: static char *
1.20 nicm 1265: any_initializer(const char *fmt, const char *type)
1.5 millert 1266: {
1267: static char *initializer;
1.24 ! nicm 1268: static size_t need;
1.5 millert 1269: char *s;
1270:
1.16 deraadt 1271: if (initializer == 0) {
1.24 ! nicm 1272: need = (strlen(entries->tterm.term_names)
! 1273: + strlen(type)
! 1274: + strlen(fmt));
! 1275: initializer = (char *) malloc(need + 1);
! 1276: if (initializer == 0)
! 1277: failed("any_initializer");
1.16 deraadt 1278: }
1.5 millert 1279:
1.24 ! nicm 1280: _nc_STRCPY(initializer, entries->tterm.term_names, need);
1.8 millert 1281: for (s = initializer; *s != 0 && *s != '|'; s++) {
1.20 nicm 1282: if (!isalnum(UChar(*s)))
1.5 millert 1283: *s = '_';
1284: }
1285: *s = 0;
1.24 ! nicm 1286: _nc_SPRINTF(s, _nc_SLIMIT(need) fmt, type);
1.5 millert 1287: return initializer;
1288: }
1289:
1.20 nicm 1290: static char *
1291: name_initializer(const char *type)
1292: {
1293: return any_initializer("_%s_data", type);
1294: }
1295:
1296: static char *
1297: string_variable(const char *type)
1298: {
1299: return any_initializer("_s_%s", type);
1300: }
1301:
1.5 millert 1302: /* dump C initializers for the terminal type */
1.8 millert 1303: static void
1.24 ! nicm 1304: dump_initializers(TERMTYPE2 *term)
1.5 millert 1305: {
1.20 nicm 1306: unsigned n;
1.5 millert 1307: const char *str = 0;
1.20 nicm 1308:
1309: printf("\nstatic char %s[] = \"%s\";\n\n",
1310: name_initializer("alias"), entries->tterm.term_names);
1311:
1312: for_each_string(n, term) {
1.24 ! nicm 1313: if (VALID_STRING(term->Strings[n])) {
! 1314: char buf[MAX_STRING], *sp, *tp;
1.20 nicm 1315:
1316: tp = buf;
1.24 ! nicm 1317: #define TP_LIMIT ((MAX_STRING - 5) - (size_t)(tp - buf))
1.20 nicm 1318: *tp++ = '"';
1319: for (sp = term->Strings[n];
1.24 ! nicm 1320: *sp != 0 && TP_LIMIT > 2;
1.20 nicm 1321: sp++) {
1322: if (isascii(UChar(*sp))
1323: && isprint(UChar(*sp))
1324: && *sp != '\\'
1325: && *sp != '"')
1326: *tp++ = *sp;
1327: else {
1.24 ! nicm 1328: _nc_SPRINTF(tp, _nc_SLIMIT(TP_LIMIT) "\\%03o", UChar(*sp));
! 1329: tp += 4;
1.20 nicm 1330: }
1331: }
1332: *tp++ = '"';
1333: *tp = '\0';
1334: (void) printf("static char %-20s[] = %s;\n",
1.24 ! nicm 1335: string_variable(ExtStrname(term, (int) n, strnames)),
! 1336: buf);
1.20 nicm 1337: }
1338: }
1339: printf("\n");
1.5 millert 1340:
1.6 millert 1341: (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL);
1.5 millert 1342:
1.8 millert 1343: for_each_boolean(n, term) {
1344: switch ((int) (term->Booleans[n])) {
1.5 millert 1345: case TRUE:
1346: str = "TRUE";
1347: break;
1348:
1349: case FALSE:
1350: str = "FALSE";
1351: break;
1352:
1353: case ABSENT_BOOLEAN:
1354: str = "ABSENT_BOOLEAN";
1355: break;
1356:
1357: case CANCELLED_BOOLEAN:
1358: str = "CANCELLED_BOOLEAN";
1359: break;
1360: }
1.20 nicm 1361: (void) printf("\t/* %3u: %-8s */\t%s,\n",
1.24 ! nicm 1362: n, ExtBoolname(term, (int) n, boolnames), str);
1.5 millert 1363: }
1364: (void) printf("%s;\n", R_CURL);
1365:
1366: (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL);
1367:
1.8 millert 1368: for_each_number(n, term) {
1369: char buf[BUFSIZ];
1370: switch (term->Numbers[n]) {
1.5 millert 1371: case ABSENT_NUMERIC:
1372: str = "ABSENT_NUMERIC";
1373: break;
1374: case CANCELLED_NUMERIC:
1375: str = "CANCELLED_NUMERIC";
1376: break;
1377: default:
1.24 ! nicm 1378: _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) "%d", term->Numbers[n]);
1.5 millert 1379: str = buf;
1380: break;
1381: }
1.20 nicm 1382: (void) printf("\t/* %3u: %-8s */\t%s,\n", n,
1.24 ! nicm 1383: ExtNumname(term, (int) n, numnames), str);
1.5 millert 1384: }
1385: (void) printf("%s;\n", R_CURL);
1386:
1387: (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL);
1388:
1.8 millert 1389: for_each_string(n, term) {
1.5 millert 1390:
1391: if (term->Strings[n] == ABSENT_STRING)
1392: str = "ABSENT_STRING";
1393: else if (term->Strings[n] == CANCELLED_STRING)
1394: str = "CANCELLED_STRING";
1.8 millert 1395: else {
1.24 ! nicm 1396: str = string_variable(ExtStrname(term, (int) n, strnames));
1.5 millert 1397: }
1.20 nicm 1398: (void) printf("\t/* %3u: %-8s */\t%s,\n", n,
1.24 ! nicm 1399: ExtStrname(term, (int) n, strnames), str);
1.20 nicm 1400: }
1401: (void) printf("%s;\n", R_CURL);
1402:
1.5 millert 1403: #if NCURSES_XNAMES
1.20 nicm 1404: if ((NUM_BOOLEANS(term) != BOOLCOUNT)
1405: || (NUM_NUMBERS(term) != NUMCOUNT)
1406: || (NUM_STRINGS(term) != STRCOUNT)) {
1407: (void) printf("static char * %s[] = %s\n",
1408: name_initializer("string_ext"), L_CURL);
1409: for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
1410: (void) printf("\t/* %3u: bool */\t\"%s\",\n",
1.24 ! nicm 1411: n, ExtBoolname(term, (int) n, boolnames));
1.20 nicm 1412: }
1413: for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
1414: (void) printf("\t/* %3u: num */\t\"%s\",\n",
1.24 ! nicm 1415: n, ExtNumname(term, (int) n, numnames));
1.20 nicm 1416: }
1417: for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
1418: (void) printf("\t/* %3u: str */\t\"%s\",\n",
1.24 ! nicm 1419: n, ExtStrname(term, (int) n, strnames));
1.5 millert 1420: }
1.20 nicm 1421: (void) printf("%s;\n", R_CURL);
1422: }
1.5 millert 1423: #endif
1424: }
1425:
1426: /* dump C initializers for the terminal type */
1.8 millert 1427: static void
1.24 ! nicm 1428: dump_termtype(TERMTYPE2 *term)
1.5 millert 1429: {
1.20 nicm 1430: (void) printf("\t%s\n\t\t%s,\n", L_CURL, name_initializer("alias"));
1.5 millert 1431: (void) printf("\t\t(char *)0,\t/* pointer to string table */\n");
1432:
1433: (void) printf("\t\t%s,\n", name_initializer("bool"));
1434: (void) printf("\t\t%s,\n", name_initializer("number"));
1435:
1436: (void) printf("\t\t%s,\n", name_initializer("string"));
1437:
1438: #if NCURSES_XNAMES
1439: (void) printf("#if NCURSES_XNAMES\n");
1440: (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n");
1441: (void) printf("\t\t%s,\t/* ...corresponding names */\n",
1.20 nicm 1442: ((NUM_BOOLEANS(term) != BOOLCOUNT)
1443: || (NUM_NUMBERS(term) != NUMCOUNT)
1444: || (NUM_STRINGS(term) != STRCOUNT))
1.11 millert 1445: ? name_initializer("string_ext")
1446: : "(char **)0");
1.5 millert 1447:
1448: (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term));
1.8 millert 1449: (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term));
1450: (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term));
1.5 millert 1451:
1.8 millert 1452: (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n",
1.11 millert 1453: NUM_BOOLEANS(term) - BOOLCOUNT);
1.8 millert 1454: (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n",
1.11 millert 1455: NUM_NUMBERS(term) - NUMCOUNT);
1.8 millert 1456: (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n",
1.11 millert 1457: NUM_STRINGS(term) - STRCOUNT);
1.5 millert 1458:
1459: (void) printf("#endif /* NCURSES_XNAMES */\n");
1.20 nicm 1460: #else
1461: (void) term;
1.5 millert 1462: #endif /* NCURSES_XNAMES */
1463: (void) printf("\t%s\n", R_CURL);
1464: }
1465:
1.11 millert 1466: static int
1467: optarg_to_number(void)
1468: {
1469: char *temp = 0;
1470: long value = strtol(optarg, &temp, 0);
1471:
1472: if (temp == 0 || temp == optarg || *temp != 0) {
1473: fprintf(stderr, "Expected a number, not \"%s\"\n", optarg);
1.20 nicm 1474: ExitProgram(EXIT_FAILURE);
1475: }
1476: return (int) value;
1477: }
1478:
1479: static char *
1480: terminal_env(void)
1481: {
1482: char *terminal;
1483:
1484: if ((terminal = getenv("TERM")) == 0) {
1485: (void) fprintf(stderr,
1486: "%s: environment variable TERM not set\n",
1487: _nc_progname);
1.11 millert 1488: exit(EXIT_FAILURE);
1489: }
1.20 nicm 1490: return terminal;
1.11 millert 1491: }
1492:
1.24 ! nicm 1493: /*
! 1494: * Show the databases that infocmp knows about. The location to which it writes is
! 1495: */
! 1496: static void
! 1497: show_databases(void)
! 1498: {
! 1499: DBDIRS state;
! 1500: int offset;
! 1501: const char *path2;
! 1502:
! 1503: _nc_first_db(&state, &offset);
! 1504: while ((path2 = _nc_next_db(&state, &offset)) != 0) {
! 1505: printf("%s\n", path2);
! 1506: }
! 1507: _nc_last_db();
! 1508: }
! 1509:
1.1 millert 1510: /***************************************************************************
1511: *
1512: * Main sequence
1513: *
1514: ***************************************************************************/
1515:
1.24 ! nicm 1516: #if NO_LEAKS
! 1517: #define MAIN_LEAKS() \
! 1518: _nc_free_termtype2(&entries[0].tterm); \
! 1519: _nc_free_termtype2(&entries[1].tterm); \
! 1520: free(myargv); \
! 1521: free(tfile); \
! 1522: free(tname)
! 1523: #else
! 1524: #define MAIN_LEAKS() /* nothing */
! 1525: #endif
! 1526:
1.8 millert 1527: int
1528: main(int argc, char *argv[])
1.1 millert 1529: {
1.8 millert 1530: /* Avoid "local data >32k" error with mwcc */
1531: /* Also avoid overflowing smaller stacks on systems like AmigaOS */
1.20 nicm 1532: path *tfile = 0;
1533: char **tname = 0;
1.24 ! nicm 1534: size_t maxterms;
1.20 nicm 1535:
1536: char **myargv;
1537:
1538: char *firstdir, *restdir;
1.24 ! nicm 1539: int c;
1.8 millert 1540: bool formatted = FALSE;
1541: bool filecompare = FALSE;
1542: int initdump = 0;
1543: bool init_analyze = FALSE;
1.20 nicm 1544: bool suppress_untranslatable = FALSE;
1.24 ! nicm 1545: int quickdump = 0;
! 1546: bool wrap_strings = FALSE;
1.21 deraadt 1547:
1.22 deraadt 1548: if (pledge("stdio rpath", NULL) == -1) {
1.24 ! nicm 1549: perror("pledge");
! 1550: exit(1);
1.22 deraadt 1551: }
1.1 millert 1552:
1.8 millert 1553: /* where is the terminfo database location going to default to? */
1554: restdir = firstdir = 0;
1555:
1.20 nicm 1556: #if NCURSES_XNAMES
1557: use_extended_names(FALSE);
1558: #endif
1.24 ! nicm 1559: _nc_strict_bsd = 0;
1.20 nicm 1560:
1561: _nc_progname = _nc_rootname(argv[0]);
1562:
1563: /* make sure we have enough space to add two terminal entries */
1564: myargv = typeCalloc(char *, (size_t) (argc + 3));
1.24 ! nicm 1565: if (myargv == 0)
! 1566: failed("myargv");
! 1567:
1.20 nicm 1568: memcpy(myargv, argv, (sizeof(char *) * (size_t) argc));
1569: argv = myargv;
1570:
1571: while ((c = getopt(argc,
1572: argv,
1.24 ! nicm 1573: "01A:aB:CcDdEeFfGgIiKLlnpQ:qR:rs:TtUuVv:Ww:x")) != -1) {
1.8 millert 1574: switch (c) {
1.24 ! nicm 1575: case '0':
! 1576: mwidth = 65535;
! 1577: mheight = 1;
! 1578: break;
! 1579:
1.20 nicm 1580: case '1':
1581: mwidth = 0;
1582: break;
1583:
1584: case 'A':
1585: firstdir = optarg;
1586: break;
1587:
1.10 millert 1588: #if NCURSES_XNAMES
1589: case 'a':
1590: _nc_disable_period = TRUE;
1591: use_extended_names(TRUE);
1592: break;
1593: #endif
1.20 nicm 1594: case 'B':
1595: restdir = optarg;
1596: break;
1597:
1.24 ! nicm 1598: case 'K':
! 1599: _nc_strict_bsd = 1;
! 1600: /* FALLTHRU */
1.20 nicm 1601: case 'C':
1602: outform = F_TERMCAP;
1603: tversion = "BSD";
1604: if (sortmode == S_DEFAULT)
1605: sortmode = S_TERMCAP;
1606: break;
1607:
1.24 ! nicm 1608: case 'D':
! 1609: show_databases();
! 1610: ExitProgram(EXIT_SUCCESS);
! 1611: break;
! 1612:
1.20 nicm 1613: case 'c':
1614: compare = C_COMMON;
1615: break;
1616:
1.8 millert 1617: case 'd':
1618: compare = C_DIFFERENCE;
1619: break;
1.1 millert 1620:
1.8 millert 1621: case 'E':
1622: initdump |= 2;
1623: break;
1.1 millert 1624:
1.20 nicm 1625: case 'e':
1626: initdump |= 1;
1.8 millert 1627: break;
1.5 millert 1628:
1.20 nicm 1629: case 'F':
1630: filecompare = TRUE;
1.8 millert 1631: break;
1.1 millert 1632:
1.8 millert 1633: case 'f':
1634: formatted = TRUE;
1635: break;
1.1 millert 1636:
1.8 millert 1637: case 'G':
1638: numbers = 1;
1639: break;
1.1 millert 1640:
1.8 millert 1641: case 'g':
1642: numbers = -1;
1643: break;
1.1 millert 1644:
1.8 millert 1645: case 'I':
1646: outform = F_TERMINFO;
1647: if (sortmode == S_DEFAULT)
1648: sortmode = S_VARIABLE;
1649: tversion = 0;
1650: break;
1.1 millert 1651:
1.8 millert 1652: case 'i':
1653: init_analyze = TRUE;
1654: break;
1.1 millert 1655:
1.8 millert 1656: case 'L':
1657: outform = F_VARIABLE;
1658: if (sortmode == S_DEFAULT)
1659: sortmode = S_VARIABLE;
1660: break;
1.1 millert 1661:
1.20 nicm 1662: case 'l':
1663: outform = F_TERMINFO;
1664: break;
1665:
1.8 millert 1666: case 'n':
1667: compare = C_NAND;
1668: break;
1.1 millert 1669:
1.8 millert 1670: case 'p':
1671: ignorepads = TRUE;
1672: break;
1.1 millert 1673:
1.24 ! nicm 1674: case 'Q':
! 1675: quickdump = optarg_to_number();
! 1676: break;
! 1677:
1.9 millert 1678: case 'q':
1679: quiet = TRUE;
1680: s_absent = "-";
1681: s_cancel = "@";
1682: bool_sep = ", ";
1683: break;
1684:
1.20 nicm 1685: case 'R':
1686: tversion = optarg;
1687: break;
1688:
1.8 millert 1689: case 'r':
1690: tversion = 0;
1691: break;
1.1 millert 1692:
1.8 millert 1693: case 's':
1694: if (*optarg == 'd')
1695: sortmode = S_NOSORT;
1696: else if (*optarg == 'i')
1697: sortmode = S_TERMINFO;
1698: else if (*optarg == 'l')
1699: sortmode = S_VARIABLE;
1700: else if (*optarg == 'c')
1701: sortmode = S_TERMCAP;
1702: else {
1703: (void) fprintf(stderr,
1.20 nicm 1704: "%s: unknown sort mode\n",
1705: _nc_progname);
1706: ExitProgram(EXIT_FAILURE);
1.8 millert 1707: }
1708: break;
1.1 millert 1709:
1.20 nicm 1710: case 'T':
1711: limited = FALSE;
1712: break;
1713:
1714: #if NCURSES_XNAMES
1715: case 't':
1716: _nc_disable_period = FALSE;
1717: suppress_untranslatable = TRUE;
1718: break;
1719: #endif
1720:
1721: case 'U':
1722: literal = TRUE;
1723: break;
1724:
1.8 millert 1725: case 'u':
1726: compare = C_USEALL;
1727: break;
1.1 millert 1728:
1.20 nicm 1729: case 'V':
1730: puts(curses_version());
1731: ExitProgram(EXIT_SUCCESS);
1732:
1.8 millert 1733: case 'v':
1.24 ! nicm 1734: itrace = (unsigned) optarg_to_number();
! 1735: use_verbosity(itrace);
! 1736: break;
! 1737:
! 1738: case 'W':
! 1739: wrap_strings = TRUE;
1.8 millert 1740: break;
1.1 millert 1741:
1.8 millert 1742: case 'w':
1.11 millert 1743: mwidth = optarg_to_number();
1.8 millert 1744: break;
1.1 millert 1745:
1.20 nicm 1746: #if NCURSES_XNAMES
1747: case 'x':
1748: use_extended_names(TRUE);
1.8 millert 1749: break;
1.20 nicm 1750: #endif
1.1 millert 1751:
1.8 millert 1752: default:
1753: usage();
1754: }
1.20 nicm 1755: }
1756:
1.24 ! nicm 1757: maxterms = (size_t) (argc + 2 - optind);
! 1758: if ((tfile = typeMalloc(path, maxterms)) == 0)
! 1759: failed("tfile");
! 1760: if ((tname = typeCalloc(char *, maxterms)) == 0)
! 1761: failed("tname");
! 1762: if ((entries = typeCalloc(ENTRY, maxterms)) == 0)
! 1763: failed("entries");
! 1764: #if NO_LEAKS
! 1765: if ((entered = typeCalloc(ENTERED, maxterms)) == 0)
! 1766: failed("entered");
! 1767: #endif
1.20 nicm 1768:
1769: if (tfile == 0
1770: || tname == 0
1771: || entries == 0) {
1772: fprintf(stderr, "%s: not enough memory\n", _nc_progname);
1773: ExitProgram(EXIT_FAILURE);
1774: }
1.1 millert 1775:
1.8 millert 1776: /* by default, sort by terminfo name */
1777: if (sortmode == S_DEFAULT)
1778: sortmode = S_TERMINFO;
1.1 millert 1779:
1.8 millert 1780: /* make sure we have at least one terminal name to work with */
1781: if (optind >= argc)
1.20 nicm 1782: argv[argc++] = terminal_env();
1.1 millert 1783:
1.8 millert 1784: /* if user is after a comparison, make sure we have two entries */
1785: if (compare != C_DEFAULT && optind >= argc - 1)
1.20 nicm 1786: argv[argc++] = terminal_env();
1.1 millert 1787:
1.24 ! nicm 1788: /* exactly one terminal name with no options means display it */
1.8 millert 1789: /* exactly two terminal names with no options means do -d */
1.24 ! nicm 1790: if (compare == C_DEFAULT) {
! 1791: switch (argc - optind) {
! 1792: default:
! 1793: fprintf(stderr, "%s: too many names to compare\n", _nc_progname);
! 1794: ExitProgram(EXIT_FAILURE);
! 1795: case 1:
! 1796: break;
! 1797: case 2:
! 1798: compare = C_DIFFERENCE;
! 1799: break;
! 1800: }
! 1801: }
! 1802:
! 1803: /* set up for display */
! 1804: dump_init(tversion, outform, sortmode,
! 1805: wrap_strings, mwidth, mheight, itrace,
! 1806: formatted, FALSE, quickdump);
1.1 millert 1807:
1.8 millert 1808: if (!filecompare) {
1809: /* grab the entries */
1810: termcount = 0;
1811: for (; optind < argc; optind++) {
1.20 nicm 1812: const char *directory = termcount ? restdir : firstdir;
1813: int status;
1.8 millert 1814:
1.20 nicm 1815: tname[termcount] = argv[optind];
1.8 millert 1816:
1.20 nicm 1817: if (directory) {
1.24 ! nicm 1818: #if NCURSES_USE_DATABASE
1.20 nicm 1819: #if MIXEDCASE_FILENAMES
1820: #define LEAF_FMT "%c"
1821: #else
1822: #define LEAF_FMT "%02x"
1823: #endif
1.24 ! nicm 1824: _nc_SPRINTF(tfile[termcount],
! 1825: _nc_SLIMIT(sizeof(path))
! 1826: "%s/" LEAF_FMT "/%s",
! 1827: directory,
! 1828: UChar(*argv[optind]), argv[optind]);
1.20 nicm 1829: if (itrace)
1830: (void) fprintf(stderr,
1831: "%s: reading entry %s from file %s\n",
1832: _nc_progname,
1833: argv[optind], tfile[termcount]);
1834:
1835: status = _nc_read_file_entry(tfile[termcount],
1.24 ! nicm 1836: &entries[termcount].tterm);
1.20 nicm 1837: #else
1838: (void) fprintf(stderr, "%s: terminfo files not supported\n",
1839: _nc_progname);
1.24 ! nicm 1840: MAIN_LEAKS();
1.20 nicm 1841: ExitProgram(EXIT_FAILURE);
1842: #endif
1843: } else {
1844: if (itrace)
1845: (void) fprintf(stderr,
1846: "%s: reading entry %s from database\n",
1847: _nc_progname,
1848: tname[termcount]);
1849:
1.24 ! nicm 1850: status = _nc_read_entry2(tname[termcount],
! 1851: tfile[termcount],
! 1852: &entries[termcount].tterm);
1.20 nicm 1853: }
1.1 millert 1854:
1.20 nicm 1855: if (status <= 0) {
1856: (void) fprintf(stderr,
1857: "%s: couldn't open terminfo file %s.\n",
1858: _nc_progname,
1859: tfile[termcount]);
1.24 ! nicm 1860: MAIN_LEAKS();
1.20 nicm 1861: ExitProgram(EXIT_FAILURE);
1.1 millert 1862: }
1.20 nicm 1863: repair_acsc(&entries[termcount].tterm);
1864: termcount++;
1.8 millert 1865: }
1.1 millert 1866:
1.2 millert 1867: #if NCURSES_XNAMES
1.8 millert 1868: if (termcount > 1)
1.9 millert 1869: _nc_align_termtype(&entries[0].tterm, &entries[1].tterm);
1.2 millert 1870: #endif
1871:
1.8 millert 1872: /* dump as C initializer for the terminal type */
1873: if (initdump) {
1874: if (initdump & 1)
1.9 millert 1875: dump_termtype(&entries[0].tterm);
1.8 millert 1876: if (initdump & 2)
1.9 millert 1877: dump_initializers(&entries[0].tterm);
1.8 millert 1878: }
1.1 millert 1879:
1.8 millert 1880: /* analyze the init strings */
1.20 nicm 1881: else if (init_analyze) {
1.1 millert 1882: #undef CUR
1.9 millert 1883: #define CUR entries[0].tterm.
1884: analyze_string("is1", init_1string, &entries[0].tterm);
1885: analyze_string("is2", init_2string, &entries[0].tterm);
1886: analyze_string("is3", init_3string, &entries[0].tterm);
1887: analyze_string("rs1", reset_1string, &entries[0].tterm);
1888: analyze_string("rs2", reset_2string, &entries[0].tterm);
1889: analyze_string("rs3", reset_3string, &entries[0].tterm);
1890: analyze_string("smcup", enter_ca_mode, &entries[0].tterm);
1891: analyze_string("rmcup", exit_ca_mode, &entries[0].tterm);
1.24 ! nicm 1892: analyze_string("smkx", keypad_xmit, &entries[0].tterm);
! 1893: analyze_string("rmkx", keypad_local, &entries[0].tterm);
1.1 millert 1894: #undef CUR
1.20 nicm 1895: } else {
1.24 ! nicm 1896: int i;
! 1897: int len;
1.1 millert 1898:
1.20 nicm 1899: /*
1900: * Here's where the real work gets done
1901: */
1902: switch (compare) {
1903: case C_DEFAULT:
1904: if (itrace)
1905: (void) fprintf(stderr,
1906: "%s: about to dump %s\n",
1907: _nc_progname,
1908: tname[0]);
1.24 ! nicm 1909: if (!quiet)
! 1910: (void)
! 1911: printf("#\tReconstructed via infocmp from file: %s\n",
! 1912: tfile[0]);
1.20 nicm 1913: dump_entry(&entries[0].tterm,
1914: suppress_untranslatable,
1915: limited,
1916: numbers,
1917: NULL);
1918: len = show_entry();
1919: if (itrace)
1920: (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
1921: break;
1.1 millert 1922:
1.20 nicm 1923: case C_DIFFERENCE:
1.24 ! nicm 1924: show_comparing(tname);
1.20 nicm 1925: compare_entry(compare_predicate, &entries->tterm, quiet);
1926: break;
1.1 millert 1927:
1.20 nicm 1928: case C_COMMON:
1.24 ! nicm 1929: show_comparing(tname);
1.20 nicm 1930: compare_entry(compare_predicate, &entries->tterm, quiet);
1931: break;
1.1 millert 1932:
1.20 nicm 1933: case C_NAND:
1.24 ! nicm 1934: show_comparing(tname);
1.20 nicm 1935: compare_entry(compare_predicate, &entries->tterm, quiet);
1936: break;
1.1 millert 1937:
1.20 nicm 1938: case C_USEALL:
1939: if (itrace)
1940: (void) fprintf(stderr, "%s: dumping use entry\n", _nc_progname);
1941: dump_entry(&entries[0].tterm,
1942: suppress_untranslatable,
1943: limited,
1944: numbers,
1945: use_predicate);
1946: for (i = 1; i < termcount; i++)
1947: dump_uses(tname[i], !(outform == F_TERMCAP
1948: || outform == F_TCONVERR));
1949: len = show_entry();
1950: if (itrace)
1951: (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
1952: break;
1953: }
1.1 millert 1954: }
1.24 ! nicm 1955: } else if (compare == C_USEALL) {
1.8 millert 1956: (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
1.24 ! nicm 1957: } else if (compare == C_DEFAULT) {
1.8 millert 1958: (void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
1.24 ! nicm 1959: } else if (argc - optind != 2) {
1.8 millert 1960: (void) fprintf(stderr,
1.11 millert 1961: "File comparison needs exactly two file arguments.\n");
1.24 ! nicm 1962: } else {
1.8 millert 1963: file_comparison(argc - optind, argv + optind);
1.24 ! nicm 1964: }
1.1 millert 1965:
1.24 ! nicm 1966: MAIN_LEAKS();
1.8 millert 1967: ExitProgram(EXIT_SUCCESS);
1.1 millert 1968: }
1969:
1970: /* infocmp.c ends here */