Annotation of src/usr.bin/infocmp/infocmp.c, Revision 1.20
1.20 ! nicm 1: /* $OpenBSD: infocmp.c,v 1.16 2003/04/06 18:41:03 deraadt Exp $ */
1.1 millert 2:
3: /****************************************************************************
1.20 ! nicm 4: * Copyright (c) 1998-2007,2008 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> *
1.20 ! nicm 34: * and: Thomas E. Dickey 1996-on *
1.1 millert 35: ****************************************************************************/
36:
37: /*
38: * infocmp.c -- decompile an entry, or compare two entries
39: * written by Eric S. Raymond
1.20 ! nicm 40: * and Thomas E Dickey
1.1 millert 41: */
42:
43: #include <progs.priv.h>
44:
45: #include <dump_entry.h>
46:
1.20 ! nicm 47: MODULE_ID("$Id: infocmp.c,v 1.103 2008/08/16 22:04:56 tom Exp $")
1.1 millert 48:
49: #define L_CURL "{"
50: #define R_CURL "}"
51:
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:
1.20 ! nicm 65: static ENTRY *entries; /* terminfo entries */
1.1 millert 66: static int termcount; /* count of terminal entries */
67:
1.9 millert 68: static bool limited = TRUE; /* "-r" option is not set */
69: static bool quiet = FALSE;
1.20 ! nicm 70: static bool literal = 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.20 ! nicm 92: static void ExitProgram(int code) GCC_NORETURN;
! 93: /* prototype is to get gcc to accept the noreturn attribute */
1.8 millert 94: static void
1.20 ! nicm 95: ExitProgram(int code)
1.1 millert 96: {
1.8 millert 97: while (termcount-- > 0)
1.9 millert 98: _nc_free_termtype(&entries[termcount].tterm);
1.8 millert 99: _nc_leaks_dump_entry();
1.20 ! nicm 100: free(entries);
! 101: _nc_free_tic(code);
1.1 millert 102: }
103: #endif
104:
1.8 millert 105: static char *
1.16 deraadt 106: canonical_name(char *ptr, char *buf, size_t bufl)
1.1 millert 107: /* extract the terminal type's primary name */
108: {
1.8 millert 109: char *bp;
1.1 millert 110:
1.16 deraadt 111: (void) strlcpy(buf, ptr, bufl);
1.9 millert 112: if ((bp = strchr(buf, '|')) != 0)
1.1 millert 113: *bp = '\0';
114:
1.8 millert 115: return (buf);
1.1 millert 116: }
117:
118: /***************************************************************************
119: *
120: * Predicates for dump function
121: *
122: ***************************************************************************/
123:
1.8 millert 124: static int
1.20 ! nicm 125: capcmp(PredIdx 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
1.20 ! nicm 140: use_predicate(unsigned type, PredIdx 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: {
1.20 ! nicm 226: unsigned i, j;
1.9 millert 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.20 ! nicm 250: entryeq(TERMTYPE *t1, TERMTYPE *t2)
1.9 millert 251: /* are two entries equivalent? */
1.1 millert 252: {
1.20 ! nicm 253: unsigned 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.20 ! nicm 264: if (capcmp((PredIdx) 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.20 ! nicm 273: print_uses(ENTRY * ep, FILE *fp)
1.9 millert 274: /* print an entry's use references */
275: {
1.20 ! nicm 276: unsigned i;
1.9 millert 277:
278: if (!ep->nuses)
279: fputs("NULL", fp);
280: else
281: for (i = 0; i < ep->nuses; i++) {
282: fputs(ep->uses[i].name, fp);
283: if (i < ep->nuses - 1)
284: fputs(" ", fp);
285: }
286: }
287:
1.10 millert 288: static const char *
1.9 millert 289: dump_boolean(int val)
290: /* display the value of a boolean capability */
291: {
292: switch (val) {
293: case ABSENT_BOOLEAN:
294: return (s_absent);
295: case CANCELLED_BOOLEAN:
296: return (s_cancel);
297: case FALSE:
298: return ("F");
299: case TRUE:
300: return ("T");
301: default:
302: return ("?");
303: }
304: }
305:
306: static void
1.16 deraadt 307: dump_numeric(int val, char *buf, size_t bufl)
1.9 millert 308: /* display the value of a boolean capability */
309: {
310: switch (val) {
311: case ABSENT_NUMERIC:
1.16 deraadt 312: strlcpy(buf, s_absent, bufl);
1.9 millert 313: break;
314: case CANCELLED_NUMERIC:
1.16 deraadt 315: strlcpy(buf, s_cancel, bufl);
1.9 millert 316: break;
317: default:
1.16 deraadt 318: snprintf(buf, bufl, "%d", val);
1.9 millert 319: break;
320: }
321: }
322:
323: static void
1.16 deraadt 324: dump_string(char *val, char *buf, size_t bufl)
1.9 millert 325: /* display the value of a string capability */
326: {
327: if (val == ABSENT_STRING)
1.16 deraadt 328: strlcpy(buf, s_absent, bufl);
1.9 millert 329: else if (val == CANCELLED_STRING)
1.16 deraadt 330: strlcpy(buf, s_cancel, bufl);
1.9 millert 331: else {
1.16 deraadt 332: snprintf(buf, bufl, "'%.*s'", MAX_STRING - 3, TIC_EXPAND(val));
1.9 millert 333: }
334: }
335:
336: static void
1.20 ! nicm 337: compare_predicate(PredType type, PredIdx idx, const char *name)
1.1 millert 338: /* predicate function to use for entry difference reports */
339: {
1.15 mpech 340: ENTRY *e1 = &entries[0];
341: ENTRY *e2 = &entries[1];
1.9 millert 342: char buf1[MAX_STRING], buf2[MAX_STRING];
343: int b1, b2;
344: int n1, n2;
1.8 millert 345: char *s1, *s2;
346:
347: switch (type) {
1.9 millert 348: case CMP_BOOLEAN:
349: b1 = e1->tterm.Booleans[idx];
350: b2 = e2->tterm.Booleans[idx];
1.8 millert 351: switch (compare) {
352: case C_DIFFERENCE:
1.9 millert 353: if (!(b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN) && b1 != b2)
354: (void) printf("\t%s: %s%s%s.\n",
1.11 millert 355: name,
356: dump_boolean(b1),
357: bool_sep,
358: dump_boolean(b2));
1.8 millert 359: break;
360:
361: case C_COMMON:
1.9 millert 362: if (b1 == b2 && b1 != ABSENT_BOOLEAN)
363: (void) printf("\t%s= %s.\n", name, dump_boolean(b1));
1.8 millert 364: break;
365:
366: case C_NAND:
1.9 millert 367: if (b1 == ABSENT_BOOLEAN && b2 == ABSENT_BOOLEAN)
1.8 millert 368: (void) printf("\t!%s.\n", name);
369: break;
370: }
371: break;
1.1 millert 372:
1.9 millert 373: case CMP_NUMBER:
374: n1 = e1->tterm.Numbers[idx];
375: n2 = e2->tterm.Numbers[idx];
1.16 deraadt 376: dump_numeric(n1, buf1, sizeof buf1);
377: dump_numeric(n2, buf2, sizeof buf2);
1.8 millert 378: switch (compare) {
379: case C_DIFFERENCE:
1.9 millert 380: if (!((n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)) && n1 != n2)
381: (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
1.8 millert 382: break;
1.1 millert 383:
1.8 millert 384: case C_COMMON:
1.9 millert 385: if (n1 != ABSENT_NUMERIC && n2 != ABSENT_NUMERIC && n1 == n2)
386: (void) printf("\t%s= %s.\n", name, buf1);
1.8 millert 387: break;
1.1 millert 388:
1.8 millert 389: case C_NAND:
1.9 millert 390: if (n1 == ABSENT_NUMERIC && n2 == ABSENT_NUMERIC)
1.8 millert 391: (void) printf("\t!%s.\n", name);
392: break;
393: }
394: break;
1.1 millert 395:
1.9 millert 396: case CMP_STRING:
397: s1 = e1->tterm.Strings[idx];
398: s2 = e2->tterm.Strings[idx];
1.8 millert 399: switch (compare) {
400: case C_DIFFERENCE:
1.9 millert 401: if (capcmp(idx, s1, s2)) {
1.16 deraadt 402: dump_string(s1, buf1, sizeof buf1);
403: dump_string(s2, buf2, sizeof buf2);
1.8 millert 404: if (strcmp(buf1, buf2))
1.9 millert 405: (void) printf("\t%s: %s, %s.\n", name, buf1, buf2);
1.8 millert 406: }
407: break;
1.1 millert 408:
1.8 millert 409: case C_COMMON:
1.9 millert 410: if (s1 && s2 && !capcmp(idx, s1, s2))
1.8 millert 411: (void) printf("\t%s= '%s'.\n", name, TIC_EXPAND(s1));
412: break;
1.1 millert 413:
1.8 millert 414: case C_NAND:
415: if (!s1 && !s2)
416: (void) printf("\t!%s.\n", name);
417: break;
1.1 millert 418: }
1.8 millert 419: break;
1.9 millert 420:
421: case CMP_USE:
422: /* unlike the other modes, this compares *all* use entries */
423: switch (compare) {
424: case C_DIFFERENCE:
425: if (!useeq(e1, e2)) {
426: (void) fputs("\tuse: ", stdout);
427: print_uses(e1, stdout);
428: fputs(", ", stdout);
429: print_uses(e2, stdout);
430: fputs(".\n", stdout);
431: }
432: break;
433:
434: case C_COMMON:
435: if (e1->nuses && e2->nuses && useeq(e1, e2)) {
436: (void) fputs("\tuse: ", stdout);
437: print_uses(e1, stdout);
438: fputs(".\n", stdout);
439: }
440: break;
441:
442: case C_NAND:
443: if (!e1->nuses && !e2->nuses)
444: (void) printf("\t!use.\n");
445: break;
446: }
1.8 millert 447: }
1.1 millert 448: }
449:
450: /***************************************************************************
451: *
452: * Init string analysis
453: *
454: ***************************************************************************/
455:
1.8 millert 456: typedef struct {
457: const char *from;
458: const char *to;
459: } assoc;
1.1 millert 460:
461: static const assoc std_caps[] =
462: {
463: /* these are specified by X.364 and iBCS2 */
1.8 millert 464: {"\033c", "RIS"}, /* full reset */
465: {"\0337", "SC"}, /* save cursor */
466: {"\0338", "RC"}, /* restore cursor */
467: {"\033[r", "RSR"}, /* not an X.364 mnemonic */
468: {"\033[m", "SGR0"}, /* not an X.364 mnemonic */
469: {"\033[2J", "ED2"}, /* clear page */
1.1 millert 470:
471: /* this group is specified by ISO 2022 */
1.8 millert 472: {"\033(0", "ISO DEC G0"}, /* enable DEC graphics for G0 */
473: {"\033(A", "ISO UK G0"}, /* enable UK chars for G0 */
474: {"\033(B", "ISO US G0"}, /* enable US chars for G0 */
475: {"\033)0", "ISO DEC G1"}, /* enable DEC graphics for G1 */
476: {"\033)A", "ISO UK G1"}, /* enable UK chars for G1 */
477: {"\033)B", "ISO US G1"}, /* enable US chars for G1 */
1.1 millert 478:
1.20 ! nicm 479: /* these are DEC private controls 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.20 ! nicm 483: {"\033[!p", "DECSTR"}, /* soft reset */
! 484: {"\033 F", "S7C1T"}, /* 7-bit controls */
1.1 millert 485:
1.8 millert 486: {(char *) 0, (char *) 0}
1.1 millert 487: };
488:
1.20 ! nicm 489: static const assoc std_modes[] =
! 490: /* ECMA \E[ ... [hl] modes recognized by many emulators */
! 491: {
! 492: {"2", "AM"}, /* keyboard action mode */
! 493: {"4", "IRM"}, /* insert/replace mode */
! 494: {"12", "SRM"}, /* send/receive mode */
! 495: {"20", "LNM"}, /* linefeed mode */
! 496: {(char *) 0, (char *) 0}
! 497: };
! 498:
1.1 millert 499: static const assoc private_modes[] =
500: /* DEC \E[ ... [hl] modes recognized by many emulators */
501: {
1.8 millert 502: {"1", "CKM"}, /* application cursor keys */
503: {"2", "ANM"}, /* set VT52 mode */
504: {"3", "COLM"}, /* 132-column mode */
505: {"4", "SCLM"}, /* smooth scroll */
506: {"5", "SCNM"}, /* reverse video mode */
507: {"6", "OM"}, /* origin mode */
508: {"7", "AWM"}, /* wraparound mode */
509: {"8", "ARM"}, /* auto-repeat mode */
510: {(char *) 0, (char *) 0}
1.1 millert 511: };
512:
513: static const assoc ecma_highlights[] =
514: /* recognize ECMA attribute sequences */
515: {
1.8 millert 516: {"0", "NORMAL"}, /* normal */
517: {"1", "+BOLD"}, /* bold on */
518: {"2", "+DIM"}, /* dim on */
519: {"3", "+ITALIC"}, /* italic on */
520: {"4", "+UNDERLINE"}, /* underline on */
521: {"5", "+BLINK"}, /* blink on */
522: {"6", "+FASTBLINK"}, /* fastblink on */
523: {"7", "+REVERSE"}, /* reverse on */
524: {"8", "+INVISIBLE"}, /* invisible on */
525: {"9", "+DELETED"}, /* deleted on */
526: {"10", "MAIN-FONT"}, /* select primary font */
527: {"11", "ALT-FONT-1"}, /* select alternate font 1 */
528: {"12", "ALT-FONT-2"}, /* select alternate font 2 */
529: {"13", "ALT-FONT-3"}, /* select alternate font 3 */
530: {"14", "ALT-FONT-4"}, /* select alternate font 4 */
531: {"15", "ALT-FONT-5"}, /* select alternate font 5 */
532: {"16", "ALT-FONT-6"}, /* select alternate font 6 */
533: {"17", "ALT-FONT-7"}, /* select alternate font 7 */
534: {"18", "ALT-FONT-1"}, /* select alternate font 1 */
535: {"19", "ALT-FONT-1"}, /* select alternate font 1 */
536: {"20", "FRAKTUR"}, /* Fraktur font */
537: {"21", "DOUBLEUNDER"}, /* double underline */
538: {"22", "-DIM"}, /* dim off */
539: {"23", "-ITALIC"}, /* italic off */
540: {"24", "-UNDERLINE"}, /* underline off */
541: {"25", "-BLINK"}, /* blink off */
542: {"26", "-FASTBLINK"}, /* fastblink off */
543: {"27", "-REVERSE"}, /* reverse off */
544: {"28", "-INVISIBLE"}, /* invisible off */
545: {"29", "-DELETED"}, /* deleted off */
546: {(char *) 0, (char *) 0}
1.1 millert 547: };
548:
1.20 ! nicm 549: static int
! 550: skip_csi(const char *cap)
! 551: {
! 552: int result = 0;
! 553: if (cap[0] == '\033' && cap[1] == '[')
! 554: result = 2;
! 555: else if (UChar(cap[0]) == 0233)
! 556: result = 1;
! 557: return result;
! 558: }
! 559:
! 560: static bool
! 561: same_param(const char *table, const char *param, unsigned length)
! 562: {
! 563: bool result = FALSE;
! 564: if (strncmp(table, param, length) == 0) {
! 565: result = !isdigit(UChar(param[length]));
! 566: }
! 567: return result;
! 568: }
! 569:
! 570: static char *
! 571: lookup_params(const assoc * table, char *dst, char *src, size_t dstlen)
! 572: {
! 573: char *result = 0;
! 574: const char *ep = strtok(src, ";");
! 575:
! 576: if (ep != 0) {
! 577: const assoc *ap;
! 578:
! 579: do {
! 580: bool found = FALSE;
! 581:
! 582: for (ap = table; ap->from; ap++) {
! 583: size_t tlen = strlen(ap->from);
! 584:
! 585: if (same_param(ap->from, ep, tlen)) {
! 586: (void) strlcat(dst, ap->to, dstlen);
! 587: found = TRUE;
! 588: break;
! 589: }
! 590: }
! 591:
! 592: if (!found)
! 593: (void) strlcat(dst, ep, dstlen);
! 594: (void) strlcat(dst, ";", dstlen);
! 595: } while
! 596: ((ep = strtok((char *) 0, ";")));
! 597:
! 598: if (dst[0] != '\0' && dst[strlen(dst) - 1] == ';')
! 599: dst[strlen(dst) - 1] = '\0';
! 600:
! 601: result = dst;
! 602: }
! 603: return result;
! 604: }
! 605:
1.8 millert 606: static void
1.20 ! nicm 607: analyze_string(const char *name, const char *cap, TERMTYPE *tp)
1.1 millert 608: {
1.8 millert 609: char buf2[MAX_TERMINFO_LENGTH];
1.20 ! nicm 610: const char *sp;
1.8 millert 611: const assoc *ap;
1.20 ! nicm 612: int tp_lines = tp->Numbers[2];
1.1 millert 613:
614: if (cap == ABSENT_STRING || cap == CANCELLED_STRING)
615: return;
616: (void) printf("%s: ", name);
617:
1.8 millert 618: for (sp = cap; *sp; sp++) {
619: int i;
1.20 ! nicm 620: int csi;
1.8 millert 621: size_t len = 0;
1.20 ! nicm 622: size_t next;
1.1 millert 623: const char *expansion = 0;
1.20 ! nicm 624: char buf3[MAX_TERMINFO_LENGTH];
1.1 millert 625:
626: /* first, check other capabilities in this entry */
1.8 millert 627: for (i = 0; i < STRCOUNT; i++) {
628: char *cp = tp->Strings[i];
1.1 millert 629:
630: /* don't use soft-key capabilities */
631: if (strnames[i][0] == 'k' && strnames[i][0] == 'f')
632: continue;
633:
1.8 millert 634: if (cp != ABSENT_STRING && cp != CANCELLED_STRING && cp[0] && cp
635: != cap) {
1.1 millert 636: len = strlen(cp);
637: (void) strncpy(buf2, sp, len);
638: buf2[len] = '\0';
639:
640: if (_nc_capcmp(cp, buf2))
641: continue;
642:
643: #define ISRS(s) (!strncmp((s), "is", 2) || !strncmp((s), "rs", 2))
644: /*
645: * Theoretically we just passed the test for translation
646: * (equality once the padding is stripped). However, there
647: * are a few more hoops that need to be jumped so that
648: * identical pairs of initialization and reset strings
649: * don't just refer to each other.
650: */
651: if (ISRS(name) || ISRS(strnames[i]))
652: if (cap < cp)
653: continue;
654: #undef ISRS
655:
656: expansion = strnames[i];
657: break;
658: }
659: }
660:
661: /* now check the standard capabilities */
1.20 ! nicm 662: if (!expansion) {
! 663: csi = skip_csi(sp);
1.8 millert 664: for (ap = std_caps; ap->from; ap++) {
1.20 ! nicm 665: size_t adj = (size_t) (csi ? 2 : 0);
! 666:
1.1 millert 667: len = strlen(ap->from);
1.20 ! nicm 668: if (csi && skip_csi(ap->from) != csi)
! 669: continue;
! 670: if (len > adj
! 671: && strncmp(ap->from + adj, sp + csi, len - adj) == 0) {
1.1 millert 672: expansion = ap->to;
1.20 ! nicm 673: len -= adj;
! 674: len += (size_t) csi;
1.1 millert 675: break;
676: }
677: }
1.20 ! nicm 678: }
! 679:
! 680: /* now check for standard-mode sequences */
! 681: if (!expansion
! 682: && (csi = skip_csi(sp)) != 0
! 683: && (len = strspn(sp + csi, "0123456789;"))
! 684: && (len < sizeof(buf3))
! 685: && (next = (size_t) csi + len)
! 686: && ((sp[next] == 'h') || (sp[next] == 'l'))) {
! 687:
! 688: (void) strlcpy(buf2, (sp[next] == 'h') ? "ECMA+" : "ECMA-",
! 689: sizeof buf2);
! 690: (void) strncpy(buf3, sp + csi, len);
! 691: buf3[len] = '\0';
! 692: len += (size_t) csi + 1;
! 693:
! 694: expansion = lookup_params(std_modes, buf2, buf3, sizeof buf2);
! 695: }
1.1 millert 696:
697: /* now check for private-mode sequences */
698: if (!expansion
1.20 ! nicm 699: && (csi = skip_csi(sp)) != 0
! 700: && sp[csi] == '?'
! 701: && (len = strspn(sp + csi + 1, "0123456789;"))
! 702: && (len < sizeof(buf3))
! 703: && (next = (size_t) csi + 1 + len)
! 704: && ((sp[next] == 'h') || (sp[next] == 'l'))) {
1.1 millert 705:
1.20 ! nicm 706: (void) strlcpy(buf2, (sp[next] == 'h') ? "DEC+" : "DEC-",
1.16 deraadt 707: sizeof buf2);
1.20 ! nicm 708: (void) strncpy(buf3, sp + csi + 1, len);
1.1 millert 709: buf3[len] = '\0';
1.20 ! nicm 710: len += (size_t) csi + 2;
1.1 millert 711:
1.20 ! nicm 712: expansion = lookup_params(private_modes, buf2, buf3, sizeof buf2);
1.1 millert 713: }
714:
715: /* now check for ECMA highlight sequences */
716: if (!expansion
1.20 ! nicm 717: && (csi = skip_csi(sp)) != 0
! 718: && (len = strspn(sp + csi, "0123456789;")) != 0
! 719: && (len < sizeof(buf3))
! 720: && (next = (size_t) csi + len)
! 721: && sp[next] == 'm') {
1.1 millert 722:
1.16 deraadt 723: (void) strlcpy(buf2, "SGR:", sizeof buf2);
1.20 ! nicm 724: (void) strncpy(buf3, sp + csi, len);
1.1 millert 725: buf3[len] = '\0';
1.20 ! nicm 726: len += (size_t) csi + 1;
1.1 millert 727:
1.20 ! nicm 728: expansion = lookup_params(ecma_highlights, buf2, buf3, sizeof buf2);
! 729: }
1.1 millert 730:
1.20 ! nicm 731: if (!expansion
! 732: && (csi = skip_csi(sp)) != 0
! 733: && sp[csi] == 'm') {
! 734: len = (size_t) csi + 1;
! 735: (void) strlcpy(buf2, "SGR:", sizeof buf2);
! 736: strlcat(buf2, ecma_highlights[0].to, sizeof buf2);
1.1 millert 737: expansion = buf2;
738: }
1.20 ! nicm 739:
1.1 millert 740: /* now check for scroll region reset */
1.20 ! nicm 741: if (!expansion
! 742: && (csi = skip_csi(sp)) != 0) {
! 743: if (sp[csi] == 'r') {
1.1 millert 744: expansion = "RSR";
1.20 ! nicm 745: len = 1;
! 746: } else {
! 747: (void) snprintf(buf2, sizeof buf2, "1;%dr", tp_lines);
! 748: len = strlen(buf2);
! 749: if (strncmp(buf2, sp + csi, len) == 0)
! 750: expansion = "RSR";
! 751: }
! 752: len += (size_t) csi;
1.1 millert 753: }
754:
755: /* now check for home-down */
1.20 ! nicm 756: if (!expansion
! 757: && (csi = skip_csi(sp)) != 0) {
! 758: (void) snprintf(buf2, sizeof buf2, "%d;1H", tp_lines);
1.1 millert 759: len = strlen(buf2);
1.20 ! nicm 760: if (strncmp(buf2, sp + csi, len) == 0) {
1.8 millert 761: expansion = "LL";
1.20 ! nicm 762: } else {
! 763: (void) snprintf(buf2, sizeof buf2, "%dH", tp_lines);
! 764: len = strlen(buf2);
! 765: if (strncmp(buf2, sp + csi, len) == 0) {
! 766: expansion = "LL";
! 767: }
! 768: }
! 769: len += (size_t) csi;
1.1 millert 770: }
771:
772: /* now look at the expansion we got, if any */
1.8 millert 773: if (expansion) {
1.20 ! nicm 774: printf("{%s}", expansion);
1.1 millert 775: sp += len - 1;
1.8 millert 776: } else {
1.1 millert 777: /* couldn't match anything */
778: buf2[0] = *sp;
779: buf2[1] = '\0';
1.20 ! nicm 780: fputs(TIC_EXPAND(buf2), stdout);
1.1 millert 781: }
782: }
1.20 ! nicm 783: putchar('\n');
1.1 millert 784: }
785:
786: /***************************************************************************
787: *
788: * File comparison
789: *
790: ***************************************************************************/
791:
1.8 millert 792: static void
793: file_comparison(int argc, char *argv[])
1.1 millert 794: {
795: #define MAXCOMPARE 2
796: /* someday we may allow comparisons on more files */
1.8 millert 797: int filecount = 0;
798: ENTRY *heads[MAXCOMPARE];
799: ENTRY *qp, *rp;
800: int i, n;
1.1 millert 801:
1.20 ! nicm 802: memset(heads, 0, sizeof(heads));
1.9 millert 803: dump_init((char *) 0, F_LITERAL, S_TERMINFO, 0, itrace, FALSE);
1.1 millert 804:
1.8 millert 805: for (n = 0; n < argc && n < MAXCOMPARE; n++) {
1.9 millert 806: if (freopen(argv[n], "r", stdin) == 0)
1.1 millert 807: _nc_err_abort("Can't open %s", argv[n]);
808:
1.9 millert 809: _nc_head = _nc_tail = 0;
1.1 millert 810:
811: /* parse entries out of the source file */
812: _nc_set_source(argv[n]);
1.20 ! nicm 813: _nc_read_entry_source(stdin, NULL, TRUE, literal, NULLHOOK);
1.1 millert 814:
815: if (itrace)
1.8 millert 816: (void) fprintf(stderr, "Resolving file %d...\n", n - 0);
1.1 millert 817:
1.9 millert 818: /* maybe do use resolution */
1.20 ! nicm 819: if (!_nc_resolve_uses2(!limited, literal)) {
1.1 millert 820: (void) fprintf(stderr,
1.11 millert 821: "There are unresolved use entries in %s:\n",
822: argv[n]);
1.9 millert 823: for_entry_list(qp) {
1.8 millert 824: if (qp->nuses) {
1.9 millert 825: (void) fputs(qp->tterm.term_names, stderr);
826: (void) fputc('\n', stderr);
827: }
1.8 millert 828: }
1.20 ! nicm 829: ExitProgram(EXIT_FAILURE);
1.1 millert 830: }
831:
832: heads[filecount] = _nc_head;
833: filecount++;
834: }
835:
836: /* OK, all entries are in core. Ready to do the comparison */
837: if (itrace)
838: (void) fprintf(stderr, "Entries are now in core...\n");
839:
1.9 millert 840: /* The entry-matching loop. Sigh, this is intrinsically quadratic. */
1.8 millert 841: for (qp = heads[0]; qp; qp = qp->next) {
1.1 millert 842: for (rp = heads[1]; rp; rp = rp->next)
1.8 millert 843: if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names)) {
1.9 millert 844: if (qp->ncrosslinks < MAX_CROSSLINKS)
845: qp->crosslinks[qp->ncrosslinks] = rp;
846: qp->ncrosslinks++;
847:
848: if (rp->ncrosslinks < MAX_CROSSLINKS)
849: rp->crosslinks[rp->ncrosslinks] = qp;
850: rp->ncrosslinks++;
1.1 millert 851: }
852: }
853:
854: /* now we have two circular lists with crosslinks */
855: if (itrace)
856: (void) fprintf(stderr, "Name matches are done...\n");
857:
1.9 millert 858: for (qp = heads[0]; qp; qp = qp->next) {
859: if (qp->ncrosslinks > 1) {
1.1 millert 860: (void) fprintf(stderr,
1.11 millert 861: "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
862: _nc_first_name(qp->tterm.term_names),
863: argv[0],
864: qp->ncrosslinks,
865: argv[1]);
1.9 millert 866: for (i = 0; i < qp->ncrosslinks; i++)
1.1 millert 867: (void) fprintf(stderr,
1.11 millert 868: "\t%s\n",
869: _nc_first_name((qp->crosslinks[i])->tterm.term_names));
1.1 millert 870: }
1.9 millert 871: }
872:
873: for (rp = heads[1]; rp; rp = rp->next) {
874: if (rp->ncrosslinks > 1) {
1.1 millert 875: (void) fprintf(stderr,
1.11 millert 876: "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
877: _nc_first_name(rp->tterm.term_names),
878: argv[1],
879: rp->ncrosslinks,
880: argv[0]);
1.9 millert 881: for (i = 0; i < rp->ncrosslinks; i++)
1.1 millert 882: (void) fprintf(stderr,
1.11 millert 883: "\t%s\n",
884: _nc_first_name((rp->crosslinks[i])->tterm.term_names));
1.1 millert 885: }
1.9 millert 886: }
1.1 millert 887:
888: (void) printf("In file 1 (%s) only:\n", argv[0]);
889: for (qp = heads[0]; qp; qp = qp->next)
1.9 millert 890: if (qp->ncrosslinks == 0)
1.1 millert 891: (void) printf("\t%s\n",
1.11 millert 892: _nc_first_name(qp->tterm.term_names));
1.1 millert 893:
894: (void) printf("In file 2 (%s) only:\n", argv[1]);
895: for (rp = heads[1]; rp; rp = rp->next)
1.9 millert 896: if (rp->ncrosslinks == 0)
1.1 millert 897: (void) printf("\t%s\n",
1.11 millert 898: _nc_first_name(rp->tterm.term_names));
1.1 millert 899:
900: (void) printf("The following entries are equivalent:\n");
1.8 millert 901: for (qp = heads[0]; qp; qp = qp->next) {
1.9 millert 902: rp = qp->crosslinks[0];
903:
904: if (qp->ncrosslinks == 1) {
905: rp = qp->crosslinks[0];
1.1 millert 906:
1.9 millert 907: repair_acsc(&qp->tterm);
908: repair_acsc(&rp->tterm);
909: #if NCURSES_XNAMES
910: _nc_align_termtype(&qp->tterm, &rp->tterm);
911: #endif
912: if (entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp)) {
913: char name1[NAMESIZE], name2[NAMESIZE];
1.1 millert 914:
1.16 deraadt 915: (void) canonical_name(qp->tterm.term_names, name1, sizeof name1);
916: (void) canonical_name(rp->tterm.term_names, name2, sizeof name2);
1.1 millert 917:
1.9 millert 918: (void) printf("%s = %s\n", name1, name2);
919: }
1.1 millert 920: }
921: }
922:
923: (void) printf("Differing entries:\n");
924: termcount = 2;
1.8 millert 925: for (qp = heads[0]; qp; qp = qp->next) {
1.1 millert 926:
1.9 millert 927: if (qp->ncrosslinks == 1) {
928: rp = qp->crosslinks[0];
1.2 millert 929: #if NCURSES_XNAMES
1.9 millert 930: /* sorry - we have to do this on each pass */
1.2 millert 931: _nc_align_termtype(&qp->tterm, &rp->tterm);
932: #endif
1.9 millert 933: if (!(entryeq(&qp->tterm, &rp->tterm) && useeq(qp, rp))) {
934: char name1[NAMESIZE], name2[NAMESIZE];
1.1 millert 935:
1.9 millert 936: entries[0] = *qp;
937: entries[1] = *rp;
1.1 millert 938:
1.16 deraadt 939: (void) canonical_name(qp->tterm.term_names, name1, sizeof name1);
940: (void) canonical_name(rp->tterm.term_names, name2, sizeof name2);
1.1 millert 941:
1.9 millert 942: switch (compare) {
943: case C_DIFFERENCE:
944: if (itrace)
945: (void) fprintf(stderr,
1.20 ! nicm 946: "%s: dumping differences\n",
! 947: _nc_progname);
1.9 millert 948: (void) printf("comparing %s to %s.\n", name1, name2);
949: compare_entry(compare_predicate, &entries->tterm, quiet);
950: break;
1.1 millert 951:
1.9 millert 952: case C_COMMON:
953: if (itrace)
954: (void) fprintf(stderr,
1.20 ! nicm 955: "%s: dumping common capabilities\n",
! 956: _nc_progname);
1.9 millert 957: (void) printf("comparing %s to %s.\n", name1, name2);
958: compare_entry(compare_predicate, &entries->tterm, quiet);
959: break;
1.1 millert 960:
1.9 millert 961: case C_NAND:
962: if (itrace)
963: (void) fprintf(stderr,
1.20 ! nicm 964: "%s: dumping differences\n",
! 965: _nc_progname);
1.9 millert 966: (void) printf("comparing %s to %s.\n", name1, name2);
967: compare_entry(compare_predicate, &entries->tterm, quiet);
968: break;
1.1 millert 969:
1.9 millert 970: }
1.1 millert 971: }
972: }
973: }
974: }
975:
1.8 millert 976: static void
977: usage(void)
1.1 millert 978: {
1.8 millert 979: static const char *tbl[] =
980: {
981: "Usage: infocmp [options] [-A directory] [-B directory] [termname...]"
982: ,""
983: ,"Options:"
984: ," -1 print single-column"
985: ," -C use termcap-names"
986: ," -F compare terminfo-files"
987: ," -I use terminfo-names"
988: ," -L use long names"
989: ," -R subset (see manpage)"
990: ," -T eliminate size limits (test)"
1.20 ! nicm 991: ," -U eliminate post-processing of entries"
1.8 millert 992: ," -V print version"
1.10 millert 993: #if NCURSES_XNAMES
994: ," -a with -F, list commented-out caps"
995: #endif
1.8 millert 996: ," -c list common capabilities"
997: ," -d list different capabilities"
998: ," -e format output for C initializer"
999: ," -E format output as C tables"
1000: ," -f with -1, format complex strings"
1001: ," -G format %{number} to %'char'"
1002: ," -g format %'char' to %{number}"
1003: ," -i analyze initialization/reset"
1004: ," -l output terminfo names"
1005: ," -n list capabilities in neither"
1006: ," -p ignore padding specifiers"
1.9 millert 1007: ," -q brief listing, removes headers"
1.8 millert 1008: ," -r with -C, output in termcap form"
1.9 millert 1009: ," -r with -F, resolve use-references"
1.8 millert 1010: ," -s [d|i|l|c] sort fields"
1.20 ! nicm 1011: #if NCURSES_XNAMES
! 1012: ," -t suppress commented-out capabilities"
! 1013: #endif
1.8 millert 1014: ," -u produce source with 'use='"
1015: ," -v number (verbose)"
1016: ," -w number (width)"
1.20 ! nicm 1017: #if NCURSES_XNAMES
! 1018: ," -x treat unknown capabilities as user-defined"
! 1019: #endif
1.8 millert 1020: };
1021: const size_t first = 3;
1.11 millert 1022: const size_t last = SIZEOF(tbl);
1.8 millert 1023: const size_t left = (last - first + 1) / 2 + first;
1024: size_t n;
1025:
1026: for (n = 0; n < left; n++) {
1027: size_t m = (n < first) ? last : n + left - first;
1028: if (m < last)
1029: fprintf(stderr, "%-40.40s%s\n", tbl[n], tbl[m]);
1030: else
1031: fprintf(stderr, "%s\n", tbl[n]);
1032: }
1.20 ! nicm 1033: ExitProgram(EXIT_FAILURE);
1.1 millert 1034: }
1035:
1.8 millert 1036: static char *
1.20 ! nicm 1037: any_initializer(const char *fmt, const char *type)
1.5 millert 1038: {
1039: static char *initializer;
1.16 deraadt 1040: static size_t len;
1.5 millert 1041: char *s;
1042:
1.16 deraadt 1043: if (initializer == 0) {
1.20 ! nicm 1044: len = strlen(entries->tterm.term_names) + strlen(type) + strlen(fmt);
1.16 deraadt 1045: initializer = (char *) malloc(len);
1046: }
1.5 millert 1047:
1.20 ! nicm 1048: (void) strlcpy(initializer, entries->tterm.term_names, len);
1.8 millert 1049: for (s = initializer; *s != 0 && *s != '|'; s++) {
1.20 ! nicm 1050: if (!isalnum(UChar(*s)))
1.5 millert 1051: *s = '_';
1052: }
1053: *s = 0;
1.20 ! nicm 1054: (void) snprintf(s, len - (s - initializer), fmt, type);
1.5 millert 1055: return initializer;
1056: }
1057:
1.20 ! nicm 1058: static char *
! 1059: name_initializer(const char *type)
! 1060: {
! 1061: return any_initializer("_%s_data", type);
! 1062: }
! 1063:
! 1064: static char *
! 1065: string_variable(const char *type)
! 1066: {
! 1067: return any_initializer("_s_%s", type);
! 1068: }
! 1069:
1.5 millert 1070: /* dump C initializers for the terminal type */
1.8 millert 1071: static void
1.20 ! nicm 1072: dump_initializers(TERMTYPE *term)
1.5 millert 1073: {
1.20 ! nicm 1074: unsigned n;
1.5 millert 1075: const char *str = 0;
1.20 ! nicm 1076:
! 1077: printf("\nstatic char %s[] = \"%s\";\n\n",
! 1078: name_initializer("alias"), entries->tterm.term_names);
! 1079:
! 1080: for_each_string(n, term) {
! 1081: char buf[MAX_STRING], *sp, *tp;
! 1082:
! 1083: if (VALID_STRING(term->Strings[n])) {
! 1084: tp = buf;
! 1085: *tp++ = '"';
! 1086: for (sp = term->Strings[n];
! 1087: *sp != 0 && (tp - buf) < MAX_STRING - 6;
! 1088: sp++) {
! 1089: if (isascii(UChar(*sp))
! 1090: && isprint(UChar(*sp))
! 1091: && *sp != '\\'
! 1092: && *sp != '"')
! 1093: *tp++ = *sp;
! 1094: else {
! 1095: (void) snprintf(tp, buf + sizeof buf - tp, "\\%03o",
! 1096: UChar(*sp));
! 1097: tp += strlen(tp);
! 1098: }
! 1099: }
! 1100: *tp++ = '"';
! 1101: *tp = '\0';
! 1102: (void) printf("static char %-20s[] = %s;\n",
! 1103: string_variable(ExtStrname(term, n, strnames)), buf);
! 1104: }
! 1105: }
! 1106: printf("\n");
1.5 millert 1107:
1.6 millert 1108: (void) printf("static char %s[] = %s\n", name_initializer("bool"), L_CURL);
1.5 millert 1109:
1.8 millert 1110: for_each_boolean(n, term) {
1111: switch ((int) (term->Booleans[n])) {
1.5 millert 1112: case TRUE:
1113: str = "TRUE";
1114: break;
1115:
1116: case FALSE:
1117: str = "FALSE";
1118: break;
1119:
1120: case ABSENT_BOOLEAN:
1121: str = "ABSENT_BOOLEAN";
1122: break;
1123:
1124: case CANCELLED_BOOLEAN:
1125: str = "CANCELLED_BOOLEAN";
1126: break;
1127: }
1.20 ! nicm 1128: (void) printf("\t/* %3u: %-8s */\t%s,\n",
1.11 millert 1129: n, ExtBoolname(term, n, boolnames), str);
1.5 millert 1130: }
1131: (void) printf("%s;\n", R_CURL);
1132:
1133: (void) printf("static short %s[] = %s\n", name_initializer("number"), L_CURL);
1134:
1.8 millert 1135: for_each_number(n, term) {
1136: char buf[BUFSIZ];
1137: switch (term->Numbers[n]) {
1.5 millert 1138: case ABSENT_NUMERIC:
1139: str = "ABSENT_NUMERIC";
1140: break;
1141: case CANCELLED_NUMERIC:
1142: str = "CANCELLED_NUMERIC";
1143: break;
1144: default:
1.16 deraadt 1145: snprintf(buf, sizeof buf, "%d", term->Numbers[n]);
1.5 millert 1146: str = buf;
1147: break;
1148: }
1.20 ! nicm 1149: (void) printf("\t/* %3u: %-8s */\t%s,\n", n,
1.11 millert 1150: ExtNumname(term, n, numnames), str);
1.5 millert 1151: }
1152: (void) printf("%s;\n", R_CURL);
1153:
1154: (void) printf("static char * %s[] = %s\n", name_initializer("string"), L_CURL);
1155:
1.8 millert 1156: for_each_string(n, term) {
1.5 millert 1157:
1158: if (term->Strings[n] == ABSENT_STRING)
1159: str = "ABSENT_STRING";
1160: else if (term->Strings[n] == CANCELLED_STRING)
1161: str = "CANCELLED_STRING";
1.8 millert 1162: else {
1.20 ! nicm 1163: str = string_variable(ExtStrname(term, n, strnames));
1.5 millert 1164: }
1.20 ! nicm 1165: (void) printf("\t/* %3u: %-8s */\t%s,\n", n,
! 1166: ExtStrname(term, n, strnames), str);
! 1167: }
! 1168: (void) printf("%s;\n", R_CURL);
! 1169:
1.5 millert 1170: #if NCURSES_XNAMES
1.20 ! nicm 1171: if ((NUM_BOOLEANS(term) != BOOLCOUNT)
! 1172: || (NUM_NUMBERS(term) != NUMCOUNT)
! 1173: || (NUM_STRINGS(term) != STRCOUNT)) {
! 1174: (void) printf("static char * %s[] = %s\n",
! 1175: name_initializer("string_ext"), L_CURL);
! 1176: for (n = BOOLCOUNT; n < NUM_BOOLEANS(term); ++n) {
! 1177: (void) printf("\t/* %3u: bool */\t\"%s\",\n",
! 1178: n, ExtBoolname(term, n, boolnames));
! 1179: }
! 1180: for (n = NUMCOUNT; n < NUM_NUMBERS(term); ++n) {
! 1181: (void) printf("\t/* %3u: num */\t\"%s\",\n",
! 1182: n, ExtNumname(term, n, numnames));
! 1183: }
! 1184: for (n = STRCOUNT; n < NUM_STRINGS(term); ++n) {
! 1185: (void) printf("\t/* %3u: str */\t\"%s\",\n",
! 1186: n, ExtStrname(term, n, strnames));
1.5 millert 1187: }
1.20 ! nicm 1188: (void) printf("%s;\n", R_CURL);
! 1189: }
1.5 millert 1190: #endif
1191: }
1192:
1193: /* dump C initializers for the terminal type */
1.8 millert 1194: static void
1.20 ! nicm 1195: dump_termtype(TERMTYPE *term)
1.5 millert 1196: {
1.20 ! nicm 1197: (void) printf("\t%s\n\t\t%s,\n", L_CURL, name_initializer("alias"));
1.5 millert 1198: (void) printf("\t\t(char *)0,\t/* pointer to string table */\n");
1199:
1200: (void) printf("\t\t%s,\n", name_initializer("bool"));
1201: (void) printf("\t\t%s,\n", name_initializer("number"));
1202:
1203: (void) printf("\t\t%s,\n", name_initializer("string"));
1204:
1205: #if NCURSES_XNAMES
1206: (void) printf("#if NCURSES_XNAMES\n");
1207: (void) printf("\t\t(char *)0,\t/* pointer to extended string table */\n");
1208: (void) printf("\t\t%s,\t/* ...corresponding names */\n",
1.20 ! nicm 1209: ((NUM_BOOLEANS(term) != BOOLCOUNT)
! 1210: || (NUM_NUMBERS(term) != NUMCOUNT)
! 1211: || (NUM_STRINGS(term) != STRCOUNT))
1.11 millert 1212: ? name_initializer("string_ext")
1213: : "(char **)0");
1.5 millert 1214:
1215: (void) printf("\t\t%d,\t\t/* count total Booleans */\n", NUM_BOOLEANS(term));
1.8 millert 1216: (void) printf("\t\t%d,\t\t/* count total Numbers */\n", NUM_NUMBERS(term));
1217: (void) printf("\t\t%d,\t\t/* count total Strings */\n", NUM_STRINGS(term));
1.5 millert 1218:
1.8 millert 1219: (void) printf("\t\t%d,\t\t/* count extensions to Booleans */\n",
1.11 millert 1220: NUM_BOOLEANS(term) - BOOLCOUNT);
1.8 millert 1221: (void) printf("\t\t%d,\t\t/* count extensions to Numbers */\n",
1.11 millert 1222: NUM_NUMBERS(term) - NUMCOUNT);
1.8 millert 1223: (void) printf("\t\t%d,\t\t/* count extensions to Strings */\n",
1.11 millert 1224: NUM_STRINGS(term) - STRCOUNT);
1.5 millert 1225:
1226: (void) printf("#endif /* NCURSES_XNAMES */\n");
1.20 ! nicm 1227: #else
! 1228: (void) term;
1.5 millert 1229: #endif /* NCURSES_XNAMES */
1230: (void) printf("\t%s\n", R_CURL);
1231: }
1232:
1.11 millert 1233: static int
1234: optarg_to_number(void)
1235: {
1236: char *temp = 0;
1237: long value = strtol(optarg, &temp, 0);
1238:
1239: if (temp == 0 || temp == optarg || *temp != 0) {
1240: fprintf(stderr, "Expected a number, not \"%s\"\n", optarg);
1.20 ! nicm 1241: ExitProgram(EXIT_FAILURE);
! 1242: }
! 1243: return (int) value;
! 1244: }
! 1245:
! 1246: static char *
! 1247: terminal_env(void)
! 1248: {
! 1249: char *terminal;
! 1250:
! 1251: if ((terminal = getenv("TERM")) == 0) {
! 1252: (void) fprintf(stderr,
! 1253: "%s: environment variable TERM not set\n",
! 1254: _nc_progname);
1.11 millert 1255: exit(EXIT_FAILURE);
1256: }
1.20 ! nicm 1257: return terminal;
1.11 millert 1258: }
1259:
1.1 millert 1260: /***************************************************************************
1261: *
1262: * Main sequence
1263: *
1264: ***************************************************************************/
1265:
1.8 millert 1266: int
1267: main(int argc, char *argv[])
1.1 millert 1268: {
1.8 millert 1269: /* Avoid "local data >32k" error with mwcc */
1270: /* Also avoid overflowing smaller stacks on systems like AmigaOS */
1.20 ! nicm 1271: path *tfile = 0;
! 1272: char **tname = 0;
! 1273: int maxterms;
! 1274:
! 1275: char **myargv;
! 1276:
! 1277: char *firstdir, *restdir;
1.8 millert 1278: int c, i, len;
1279: bool formatted = FALSE;
1280: bool filecompare = FALSE;
1281: int initdump = 0;
1282: bool init_analyze = FALSE;
1.20 ! nicm 1283: bool suppress_untranslatable = FALSE;
1.1 millert 1284:
1.8 millert 1285: /* where is the terminfo database location going to default to? */
1286: restdir = firstdir = 0;
1287:
1.20 ! nicm 1288: #if NCURSES_XNAMES
! 1289: use_extended_names(FALSE);
! 1290: #endif
! 1291:
! 1292: _nc_progname = _nc_rootname(argv[0]);
! 1293:
! 1294: /* make sure we have enough space to add two terminal entries */
! 1295: myargv = typeCalloc(char *, (size_t) (argc + 3));
! 1296: memcpy(myargv, argv, (sizeof(char *) * (size_t) argc));
! 1297: argv = myargv;
! 1298:
! 1299: while ((c = getopt(argc,
! 1300: argv,
! 1301: "1A:aB:CcdEeFfGgIiLlnpqR:rs:TtUuVv:w:x")) != -1) {
1.8 millert 1302: switch (c) {
1.20 ! nicm 1303: case '1':
! 1304: mwidth = 0;
! 1305: break;
! 1306:
! 1307: case 'A':
! 1308: firstdir = optarg;
! 1309: break;
! 1310:
1.10 millert 1311: #if NCURSES_XNAMES
1312: case 'a':
1313: _nc_disable_period = TRUE;
1314: use_extended_names(TRUE);
1315: break;
1316: #endif
1.20 ! nicm 1317: case 'B':
! 1318: restdir = optarg;
! 1319: break;
! 1320:
! 1321: case 'C':
! 1322: outform = F_TERMCAP;
! 1323: tversion = "BSD";
! 1324: if (sortmode == S_DEFAULT)
! 1325: sortmode = S_TERMCAP;
! 1326: break;
! 1327:
! 1328: case 'c':
! 1329: compare = C_COMMON;
! 1330: break;
! 1331:
1.8 millert 1332: case 'd':
1333: compare = C_DIFFERENCE;
1334: break;
1.1 millert 1335:
1.8 millert 1336: case 'E':
1337: initdump |= 2;
1338: break;
1.1 millert 1339:
1.20 ! nicm 1340: case 'e':
! 1341: initdump |= 1;
1.8 millert 1342: break;
1.5 millert 1343:
1.20 ! nicm 1344: case 'F':
! 1345: filecompare = TRUE;
1.8 millert 1346: break;
1.1 millert 1347:
1.8 millert 1348: case 'f':
1349: formatted = TRUE;
1350: break;
1.1 millert 1351:
1.8 millert 1352: case 'G':
1353: numbers = 1;
1354: break;
1.1 millert 1355:
1.8 millert 1356: case 'g':
1357: numbers = -1;
1358: break;
1.1 millert 1359:
1.8 millert 1360: case 'I':
1361: outform = F_TERMINFO;
1362: if (sortmode == S_DEFAULT)
1363: sortmode = S_VARIABLE;
1364: tversion = 0;
1365: break;
1.1 millert 1366:
1.8 millert 1367: case 'i':
1368: init_analyze = TRUE;
1369: break;
1.1 millert 1370:
1.8 millert 1371: case 'L':
1372: outform = F_VARIABLE;
1373: if (sortmode == S_DEFAULT)
1374: sortmode = S_VARIABLE;
1375: break;
1.1 millert 1376:
1.20 ! nicm 1377: case 'l':
! 1378: outform = F_TERMINFO;
! 1379: break;
! 1380:
1.8 millert 1381: case 'n':
1382: compare = C_NAND;
1383: break;
1.1 millert 1384:
1.8 millert 1385: case 'p':
1386: ignorepads = TRUE;
1387: break;
1.1 millert 1388:
1.9 millert 1389: case 'q':
1390: quiet = TRUE;
1391: s_absent = "-";
1392: s_cancel = "@";
1393: bool_sep = ", ";
1394: break;
1395:
1.20 ! nicm 1396: case 'R':
! 1397: tversion = optarg;
! 1398: break;
! 1399:
1.8 millert 1400: case 'r':
1401: tversion = 0;
1402: break;
1.1 millert 1403:
1.8 millert 1404: case 's':
1405: if (*optarg == 'd')
1406: sortmode = S_NOSORT;
1407: else if (*optarg == 'i')
1408: sortmode = S_TERMINFO;
1409: else if (*optarg == 'l')
1410: sortmode = S_VARIABLE;
1411: else if (*optarg == 'c')
1412: sortmode = S_TERMCAP;
1413: else {
1414: (void) fprintf(stderr,
1.20 ! nicm 1415: "%s: unknown sort mode\n",
! 1416: _nc_progname);
! 1417: ExitProgram(EXIT_FAILURE);
1.8 millert 1418: }
1419: break;
1.1 millert 1420:
1.20 ! nicm 1421: case 'T':
! 1422: limited = FALSE;
! 1423: break;
! 1424:
! 1425: #if NCURSES_XNAMES
! 1426: case 't':
! 1427: _nc_disable_period = FALSE;
! 1428: suppress_untranslatable = TRUE;
! 1429: break;
! 1430: #endif
! 1431:
! 1432: case 'U':
! 1433: literal = TRUE;
! 1434: break;
! 1435:
1.8 millert 1436: case 'u':
1437: compare = C_USEALL;
1438: break;
1.1 millert 1439:
1.20 ! nicm 1440: case 'V':
! 1441: puts(curses_version());
! 1442: ExitProgram(EXIT_SUCCESS);
! 1443:
1.8 millert 1444: case 'v':
1.11 millert 1445: itrace = optarg_to_number();
1.8 millert 1446: set_trace_level(itrace);
1447: break;
1.1 millert 1448:
1.8 millert 1449: case 'w':
1.11 millert 1450: mwidth = optarg_to_number();
1.8 millert 1451: break;
1.1 millert 1452:
1.20 ! nicm 1453: #if NCURSES_XNAMES
! 1454: case 'x':
! 1455: use_extended_names(TRUE);
1.8 millert 1456: break;
1.20 ! nicm 1457: #endif
1.1 millert 1458:
1.8 millert 1459: default:
1460: usage();
1461: }
1.20 ! nicm 1462: }
! 1463:
! 1464: maxterms = (argc + 2 - optind);
! 1465: tfile = typeMalloc(path, maxterms);
! 1466: tname = typeCalloc(char *, maxterms);
! 1467: entries = typeCalloc(ENTRY, maxterms);
! 1468:
! 1469: if (tfile == 0
! 1470: || tname == 0
! 1471: || entries == 0) {
! 1472: fprintf(stderr, "%s: not enough memory\n", _nc_progname);
! 1473: ExitProgram(EXIT_FAILURE);
! 1474: }
1.1 millert 1475:
1.8 millert 1476: /* by default, sort by terminfo name */
1477: if (sortmode == S_DEFAULT)
1478: sortmode = S_TERMINFO;
1.1 millert 1479:
1.8 millert 1480: /* set up for display */
1481: dump_init(tversion, outform, sortmode, mwidth, itrace, formatted);
1.1 millert 1482:
1.8 millert 1483: /* make sure we have at least one terminal name to work with */
1484: if (optind >= argc)
1.20 ! nicm 1485: argv[argc++] = terminal_env();
1.1 millert 1486:
1.8 millert 1487: /* if user is after a comparison, make sure we have two entries */
1488: if (compare != C_DEFAULT && optind >= argc - 1)
1.20 ! nicm 1489: argv[argc++] = terminal_env();
1.1 millert 1490:
1.8 millert 1491: /* exactly two terminal names with no options means do -d */
1492: if (argc - optind == 2 && compare == C_DEFAULT)
1493: compare = C_DIFFERENCE;
1.1 millert 1494:
1.8 millert 1495: if (!filecompare) {
1496: /* grab the entries */
1497: termcount = 0;
1498: for (; optind < argc; optind++) {
1.20 ! nicm 1499: const char *directory = termcount ? restdir : firstdir;
! 1500: int status;
1.8 millert 1501:
1.20 ! nicm 1502: tname[termcount] = argv[optind];
1.8 millert 1503:
1.20 ! nicm 1504: if (directory) {
! 1505: #if USE_DATABASE
! 1506: #if MIXEDCASE_FILENAMES
! 1507: #define LEAF_FMT "%c"
! 1508: #else
! 1509: #define LEAF_FMT "%02x"
! 1510: #endif
! 1511: (void) snprintf(tfile[termcount], sizeof (path),
! 1512: "%s/" LEAF_FMT "/%s", directory,
! 1513: UChar(*argv[optind]), argv[optind]);
! 1514: if (itrace)
! 1515: (void) fprintf(stderr,
! 1516: "%s: reading entry %s from file %s\n",
! 1517: _nc_progname,
! 1518: argv[optind], tfile[termcount]);
! 1519:
! 1520: status = _nc_read_file_entry(tfile[termcount],
! 1521: &entries[termcount].tterm);
! 1522: #else
! 1523: (void) fprintf(stderr, "%s: terminfo files not supported\n",
! 1524: _nc_progname);
! 1525: ExitProgram(EXIT_FAILURE);
! 1526: #endif
! 1527: } else {
! 1528: if (itrace)
! 1529: (void) fprintf(stderr,
! 1530: "%s: reading entry %s from database\n",
! 1531: _nc_progname,
! 1532: tname[termcount]);
! 1533:
! 1534: status = _nc_read_entry(tname[termcount],
! 1535: tfile[termcount],
! 1536: &entries[termcount].tterm);
! 1537: directory = TERMINFO; /* for error message */
! 1538: }
1.1 millert 1539:
1.20 ! nicm 1540: if (status <= 0) {
! 1541: (void) fprintf(stderr,
! 1542: "%s: couldn't open terminfo file %s.\n",
! 1543: _nc_progname,
! 1544: tfile[termcount]);
! 1545: ExitProgram(EXIT_FAILURE);
1.1 millert 1546: }
1.20 ! nicm 1547: repair_acsc(&entries[termcount].tterm);
! 1548: termcount++;
1.8 millert 1549: }
1.1 millert 1550:
1.2 millert 1551: #if NCURSES_XNAMES
1.8 millert 1552: if (termcount > 1)
1.9 millert 1553: _nc_align_termtype(&entries[0].tterm, &entries[1].tterm);
1.2 millert 1554: #endif
1555:
1.8 millert 1556: /* dump as C initializer for the terminal type */
1557: if (initdump) {
1558: if (initdump & 1)
1.9 millert 1559: dump_termtype(&entries[0].tterm);
1.8 millert 1560: if (initdump & 2)
1.9 millert 1561: dump_initializers(&entries[0].tterm);
1.8 millert 1562: }
1.1 millert 1563:
1.8 millert 1564: /* analyze the init strings */
1.20 ! nicm 1565: else if (init_analyze) {
1.1 millert 1566: #undef CUR
1.9 millert 1567: #define CUR entries[0].tterm.
1568: analyze_string("is1", init_1string, &entries[0].tterm);
1569: analyze_string("is2", init_2string, &entries[0].tterm);
1570: analyze_string("is3", init_3string, &entries[0].tterm);
1571: analyze_string("rs1", reset_1string, &entries[0].tterm);
1572: analyze_string("rs2", reset_2string, &entries[0].tterm);
1573: analyze_string("rs3", reset_3string, &entries[0].tterm);
1574: analyze_string("smcup", enter_ca_mode, &entries[0].tterm);
1575: analyze_string("rmcup", exit_ca_mode, &entries[0].tterm);
1.1 millert 1576: #undef CUR
1.20 ! nicm 1577: } else {
1.1 millert 1578:
1.20 ! nicm 1579: /*
! 1580: * Here's where the real work gets done
! 1581: */
! 1582: switch (compare) {
! 1583: case C_DEFAULT:
! 1584: if (itrace)
! 1585: (void) fprintf(stderr,
! 1586: "%s: about to dump %s\n",
! 1587: _nc_progname,
! 1588: tname[0]);
! 1589: (void) printf("#\tReconstructed via infocmp from file: %s\n",
! 1590: tfile[0]);
! 1591: dump_entry(&entries[0].tterm,
! 1592: suppress_untranslatable,
! 1593: limited,
! 1594: numbers,
! 1595: NULL);
! 1596: len = show_entry();
! 1597: if (itrace)
! 1598: (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
! 1599: break;
1.1 millert 1600:
1.20 ! nicm 1601: case C_DIFFERENCE:
! 1602: if (itrace)
! 1603: (void) fprintf(stderr, "%s: dumping differences\n", _nc_progname);
! 1604: (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
! 1605: compare_entry(compare_predicate, &entries->tterm, quiet);
! 1606: break;
1.1 millert 1607:
1.20 ! nicm 1608: case C_COMMON:
! 1609: if (itrace)
! 1610: (void) fprintf(stderr,
! 1611: "%s: dumping common capabilities\n",
! 1612: _nc_progname);
! 1613: (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
! 1614: compare_entry(compare_predicate, &entries->tterm, quiet);
! 1615: break;
1.1 millert 1616:
1.20 ! nicm 1617: case C_NAND:
! 1618: if (itrace)
! 1619: (void) fprintf(stderr,
! 1620: "%s: dumping differences\n",
! 1621: _nc_progname);
! 1622: (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
! 1623: compare_entry(compare_predicate, &entries->tterm, quiet);
! 1624: break;
1.1 millert 1625:
1.20 ! nicm 1626: case C_USEALL:
! 1627: if (itrace)
! 1628: (void) fprintf(stderr, "%s: dumping use entry\n", _nc_progname);
! 1629: dump_entry(&entries[0].tterm,
! 1630: suppress_untranslatable,
! 1631: limited,
! 1632: numbers,
! 1633: use_predicate);
! 1634: for (i = 1; i < termcount; i++)
! 1635: dump_uses(tname[i], !(outform == F_TERMCAP
! 1636: || outform == F_TCONVERR));
! 1637: len = show_entry();
! 1638: if (itrace)
! 1639: (void) fprintf(stderr, "%s: length %d\n", _nc_progname, len);
! 1640: break;
! 1641: }
1.1 millert 1642: }
1.8 millert 1643: } else if (compare == C_USEALL)
1644: (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
1645: else if (compare == C_DEFAULT)
1646: (void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
1647: else if (argc - optind != 2)
1648: (void) fprintf(stderr,
1.11 millert 1649: "File comparison needs exactly two file arguments.\n");
1.8 millert 1650: else
1651: file_comparison(argc - optind, argv + optind);
1.1 millert 1652:
1.20 ! nicm 1653: #if NO_LEAKS
! 1654: free(myargv);
! 1655: free(tfile);
! 1656: free(tname);
! 1657: #endif
1.8 millert 1658: ExitProgram(EXIT_SUCCESS);
1.1 millert 1659: }
1660:
1661: /* infocmp.c ends here */