2 /***************************************************************************
4 ****************************************************************************
5 * ncurses is copyright (C) 1992-1995 *
7 * zmbenhal@netcom.com *
9 * esr@snark.thyrsus.com *
11 * Permission is hereby granted to reproduce and distribute ncurses *
12 * by any means and for any fee, whether alone or as part of a *
13 * larger distribution, in source or in binary form, PROVIDED *
14 * this notice is included with any such distribution, and is not *
15 * removed from any of its header files. Mention of ncurses in any *
16 * applications linked with it is highly appreciated. *
18 * ncurses comes AS IS with no warranty, implied or expressed. *
20 ***************************************************************************/
24 * infocmp.c -- decompile an entry, or compare two entries
25 * written by Eric S. Raymond
28 #include <progs.priv.h>
32 #include <term_entry.h>
33 #include <dump_entry.h>
35 MODULE_ID("$Id: infocmp.c,v 1.27 1997/02/15 18:54:44 tom Exp $")
40 #define VALID_STRING(s) ((s) != CANCELLED_STRING && (s) != ABSENT_STRING)
42 #define MAXTERMS 32 /* max # terminal arguments we can handle */
44 const char *_nc_progname = "infocmp";
46 typedef char path[PATH_MAX];
48 /***************************************************************************
50 * The following control variables, together with the contents of the
51 * terminfo entries, completely determine the actions of the program.
53 ***************************************************************************/
55 static char *tname[MAXTERMS]; /* terminal type names */
56 static TERMTYPE term[MAXTERMS]; /* terminfo entries */
57 static int termcount; /* count of terminal entries */
59 static const char *tversion; /* terminfo version selected */
60 static int outform; /* output format */
61 static int sortmode; /* sort_mode */
62 static int itrace; /* trace flag for debugging */
63 static int mwidth = 60;
65 /* main comparison mode */
67 #define C_DEFAULT 0 /* don't force comparison mode */
68 #define C_DIFFERENCE 1 /* list differences between two terminals */
69 #define C_COMMON 2 /* list common capabilities */
70 #define C_NAND 3 /* list capabilities in neither terminal */
71 #define C_USEALL 4 /* generate relative use-form entry */
72 static bool ignorepads; /* ignore pad prefixes when diffing */
76 static void ExitProgram(int code) GCC_NORETURN;
77 static void ExitProgram(int code)
79 while (termcount-- > 0)
80 _nc_free_termtype(&term[termcount], FALSE);
81 _nc_leaks_dump_entry();
82 _nc_free_and_exit(code);
86 static char *canonical_name(char *ptr, char *buf)
87 /* extract the terminal type's primary name */
91 (void) strcpy(buf, ptr);
92 if ((bp = strchr(buf, '|')) != (char *)NULL)
98 /***************************************************************************
100 * Predicates for dump function
102 ***************************************************************************/
104 static int capcmp(const char *s, const char *t)
105 /* capability comparison function */
107 if (!VALID_STRING(s) && !VALID_STRING(t))
109 else if (!VALID_STRING(s) || !VALID_STRING(t))
113 return(_nc_capcmp(s, t));
115 return(strcmp(s, t));
118 static int use_predicate(int type, int idx)
119 /* predicate function to use for use decompilation */
129 * This assumes that multiple use entries are supposed
130 * to contribute the logical or of their boolean capabilities.
131 * This is true if we take the semantics of multiple uses to
132 * be 'each capability gets the first non-default value found
133 * in the sequence of use entries'.
135 for (tp = &term[1]; tp < term + termcount; tp++)
136 if (tp->Booleans[idx]) {
140 if (is_set != term->Booleans[idx])
147 int value = ABSENT_NUMERIC;
150 * We take the semantics of multiple uses to be 'each
151 * capability gets the first non-default value found
152 * in the sequence of use entries'.
154 for (tp = &term[1]; tp < term + termcount; tp++)
155 if (tp->Numbers[idx] >= 0) {
156 value = tp->Numbers[idx];
160 if (value != term->Numbers[idx])
161 return(value != ABSENT_NUMERIC);
167 char *termstr, *usestr = ABSENT_STRING;
169 termstr = term->Strings[idx];
172 * We take the semantics of multiple uses to be 'each
173 * capability gets the first non-default value found
174 * in the sequence of use entries'.
176 for (tp = &term[1]; tp < term + termcount; tp++)
177 if (tp->Strings[idx])
179 usestr = tp->Strings[idx];
183 if (usestr == ABSENT_STRING && termstr == ABSENT_STRING)
185 else if (!usestr || !termstr || capcmp(usestr,termstr))
192 return(FALSE); /* pacify compiler */
195 static bool entryeq(TERMTYPE *t1, TERMTYPE *t2)
196 /* are two terminal types equal */
200 for (i = 0; i < BOOLCOUNT; i++)
201 if (t1->Booleans[i] != t2->Booleans[i])
204 for (i = 0; i < NUMCOUNT; i++)
205 if (t1->Numbers[i] != t2->Numbers[i])
208 for (i = 0; i < STRCOUNT; i++)
209 if (capcmp(t1->Strings[i], t2->Strings[i]))
215 static void compare_predicate(int type, int idx, const char *name)
216 /* predicate function to use for entry difference reports */
218 register TERMTYPE *t1 = &term[0];
219 register TERMTYPE *t2 = &term[1];
228 if (t1->Booleans[idx] != t2->Booleans[idx])
229 (void) printf("\t%s: %c:%c.\n",
231 t1->Booleans[idx] ? 'T' : 'F',
232 t2->Booleans[idx] ? 'T' : 'F');
236 if (t1->Booleans[idx] && t2->Booleans[idx])
237 (void) printf("\t%s= T.\n", name);
241 if (!t1->Booleans[idx] && !t2->Booleans[idx])
242 (void) printf("\t!%s.\n", name);
251 if (t1->Numbers[idx] != t2->Numbers[idx])
252 (void) printf("\t%s: %d:%d.\n",
253 name, t1->Numbers[idx], t2->Numbers[idx]);
257 if (t1->Numbers[idx]!=-1 && t2->Numbers[idx]!=-1
258 && t1->Numbers[idx] == t2->Numbers[idx])
259 (void) printf("\t%s= %d.\n", name, t1->Numbers[idx]);
263 if (t1->Numbers[idx]==-1 && t2->Numbers[idx] == -1)
264 (void) printf("\t!%s.\n", name);
270 s1 = t1->Strings[idx];
271 s2 = t2->Strings[idx];
277 char buf1[BUFSIZ], buf2[BUFSIZ];
279 if (s1 == (char *)NULL)
280 (void) strcpy(buf1, "NULL");
283 (void) strcpy(buf1, "'");
284 (void) strcat(buf1, expand(s1));
285 (void) strcat(buf1, "'");
288 if (s2 == (char *)NULL)
289 (void) strcpy(buf2, "NULL");
292 (void) strcpy(buf2, "'");
293 (void) strcat(buf2, expand(s2));
294 (void) strcat(buf2, "'");
297 (void) printf("\t%s: %s, %s.\n",
303 if (s1 && s2 && !capcmp(s1, s2))
304 (void) printf("\t%s= '%s'.\n",name,expand(s1));
309 (void) printf("\t!%s.\n", name);
317 /***************************************************************************
319 * Init string analysis
321 ***************************************************************************/
323 typedef struct {const char *from; const char *to;} assoc;
325 static const assoc std_caps[] =
327 /* these are specified by X.364 and iBCS2 */
328 {"\033c", "RIS"}, /* full reset */
329 {"\0337", "SC"}, /* save cursor */
330 {"\0338", "RC"}, /* restore cursor */
331 {"\033[r", "RSR"}, /* not an X.364 mnemonic */
332 {"\033[m", "SGR0"}, /* not an X.364 mnemonic */
333 {"\033[2J", "ED2"}, /* clear page */
335 /* this group is specified by ISO 2022 */
336 {"\033(0", "ISO DEC G0"}, /* enable DEC graphics for G0 */
337 {"\033(A", "ISO UK G0"}, /* enable UK chars for G0 */
338 {"\033(B", "ISO US G0"}, /* enable US chars for G0 */
339 {"\033)0", "ISO DEC G1"}, /* enable DEC graphics for G1 */
340 {"\033)A", "ISO UK G1"}, /* enable UK chars for G1 */
341 {"\033)B", "ISO US G1"}, /* enable US chars for G1 */
343 /* these are DEC private modes widely supported by emulators */
344 {"\033=", "DECPAM"}, /* application keypad mode */
345 {"\033>", "DECPNM"}, /* normal keypad mode */
346 {"\033<", "DECANSI"}, /* enter ANSI mode */
348 { (char *)0, (char *)0}
351 static const assoc private_modes[] =
352 /* DEC \E[ ... [hl] modes recognized by many emulators */
354 {"1", "CKM"}, /* application cursor keys */
355 {"2", "ANM"}, /* set VT52 mode */
356 {"3", "COLM"}, /* 132-column mode */
357 {"4", "SCLM"}, /* smooth scroll */
358 {"5", "SCNM"}, /* reverse video mode */
359 {"6", "OM"}, /* origin mode */
360 {"7", "AWM"}, /* wraparound mode */
361 {"8", "ARM"}, /* auto-repeat mode */
362 {(char *)0, (char *)0}
365 static const assoc ecma_highlights[] =
366 /* recognize ECMA attribute sequences */
368 {"0", "NORMAL"}, /* normal */
369 {"1", "+BOLD"}, /* bold on */
370 {"2", "+DIM"}, /* dim on */
371 {"3", "+ITALIC"}, /* italic on */
372 {"4", "+UNDERLINE"}, /* underline on */
373 {"5", "+BLINK"}, /* blink on */
374 {"6", "+FASTBLINK"}, /* fastblink on */
375 {"7", "+REVERSE"}, /* reverse on */
376 {"8", "+INVISIBLE"}, /* invisible on */
377 {"9", "+DELETED"}, /* deleted on */
378 {"10", "MAIN-FONT"}, /* select primary font */
379 {"11", "ALT-FONT-1"}, /* select alternate font 1 */
380 {"12", "ALT-FONT-2"}, /* select alternate font 2 */
381 {"13", "ALT-FONT-3"}, /* select alternate font 3 */
382 {"14", "ALT-FONT-4"}, /* select alternate font 4 */
383 {"15", "ALT-FONT-5"}, /* select alternate font 5 */
384 {"16", "ALT-FONT-6"}, /* select alternate font 6 */
385 {"17", "ALT-FONT-7"}, /* select alternate font 7 */
386 {"18", "ALT-FONT-1"}, /* select alternate font 1 */
387 {"19", "ALT-FONT-1"}, /* select alternate font 1 */
388 {"20", "FRAKTUR"}, /* Fraktur font */
389 {"21", "DOUBLEUNDER"}, /* double underline */
390 {"22", "-DIM"}, /* dim off */
391 {"23", "-ITALIC"}, /* italic off */
392 {"24", "-UNDERLINE"}, /* underline off */
393 {"25", "-BLINK"}, /* blink off */
394 {"26", "-FASTBLINK"}, /* fastblink off */
395 {"27", "-REVERSE"}, /* reverse off */
396 {"28", "-INVISIBLE"}, /* invisible off */
397 {"29", "-DELETED"}, /* deleted off */
398 {(char *)0, (char *)0}
401 static void analyze_string(const char *name, const char *cap, TERMTYPE *tp)
403 char buf[MAX_TERMINFO_LENGTH];
404 char buf2[MAX_TERMINFO_LENGTH];
408 if (cap == ABSENT_STRING || cap == CANCELLED_STRING)
410 (void) printf("%s: ", name);
413 for (sp = cap; *sp; sp++)
417 const char *expansion = 0;
419 /* first, check other capabilities in this entry */
420 for (i = 0; i < STRCOUNT; i++)
422 char *cp = tp->Strings[i];
424 /* don't use soft-key capabilities */
425 if (strnames[i][0] == 'k' && strnames[i][0] == 'f')
429 if (cp != ABSENT_STRING && cp != CANCELLED_STRING && cp[0] && cp != cap)
432 (void) strncpy(buf2, sp, len);
435 if (_nc_capcmp(cp, buf2))
438 #define ISRS(s) (!strncmp((s), "is", 2) || !strncmp((s), "rs", 2))
440 * Theoretically we just passed the test for translation
441 * (equality once the padding is stripped). However, there
442 * are a few more hoops that need to be jumped so that
443 * identical pairs of initialization and reset strings
444 * don't just refer to each other.
446 if (ISRS(name) || ISRS(strnames[i]))
451 expansion = strnames[i];
456 /* now check the standard capabilities */
458 for (ap = std_caps; ap->from; ap++)
460 len = strlen(ap->from);
462 if (strncmp(ap->from, sp, len) == 0)
469 /* now check for private-mode sequences */
471 && sp[0] == '\033' && sp[1] == '[' && sp[2] == '?'
472 && (len = strspn(sp + 3, "0123456789;"))
473 && ((sp[3 + len] == 'h') || (sp[3 + len] == 'l')))
475 char buf3[MAX_TERMINFO_LENGTH];
477 (void) strcpy(buf2, (sp[3 + len] == 'h') ? "DEC+" : "DEC-");
478 (void) strncpy(buf3, sp + 3, len);
482 ep = strtok(buf3, ";");
486 for (ap = private_modes; ap->from; ap++)
488 size_t tlen = strlen(ap->from);
490 if (strncmp(ap->from, ep, tlen) == 0)
492 (void) strcat(buf2, ap->to);
499 (void) strcat(buf2, ep);
500 (void) strcat(buf2, ";");
502 ((ep = strtok((char *)NULL, ";")));
503 buf2[strlen(buf2) - 1] = '\0';
507 /* now check for ECMA highlight sequences */
509 && sp[0] == '\033' && sp[1] == '['
510 && (len = strspn(sp + 2, "0123456789;"))
511 && sp[2 + len] == 'm')
513 char buf3[MAX_TERMINFO_LENGTH];
515 (void) strcpy(buf2, "SGR:");
516 (void) strncpy(buf3, sp + 2, len);
520 ep = strtok(buf3, ";");
524 for (ap = ecma_highlights; ap->from; ap++)
526 size_t tlen = strlen(ap->from);
528 if (strncmp(ap->from, ep, tlen) == 0)
530 (void) strcat(buf2, ap->to);
537 (void) strcat(buf2, ep);
538 (void) strcat(buf2, ";");
540 ((ep = strtok((char *)NULL, ";")));
542 buf2[strlen(buf2) - 1] = '\0';
545 /* now check for scroll region reset */
548 (void) sprintf(buf2, "\033[1;%dr", tp->Numbers[2]);
550 if (strncmp(buf2, sp, len) == 0)
554 /* now check for home-down */
557 (void) sprintf(buf2, "\033[%d;1H", tp->Numbers[2]);
559 if (strncmp(buf2, sp, len) == 0)
563 /* now look at the expansion we got, if any */
566 (void) sprintf(buf + strlen(buf), "{%s}", expansion);
572 /* couldn't match anything */
575 (void) strcat(buf, expand(buf2));
578 (void) printf("%s\n", buf);
581 /***************************************************************************
585 ***************************************************************************/
587 static void file_comparison(int argc, char *argv[])
590 /* someday we may allow comparisons on more files */
592 ENTRY *heads[MAXCOMPARE];
593 ENTRY *tails[MAXCOMPARE];
597 dump_init((char *)NULL, F_LITERAL, S_TERMINFO, 0, itrace);
599 for (n = 0; n < argc && n < MAXCOMPARE; n++)
601 if (freopen(argv[n], "r", stdin) == NULL)
602 _nc_err_abort("Can't open %s", argv[n]);
604 _nc_head = _nc_tail = (ENTRY *)NULL;
606 /* parse entries out of the source file */
607 _nc_set_source(argv[n]);
608 _nc_read_entry_source(stdin, NULL, TRUE, FALSE, NULLHOOK);
611 (void) fprintf(stderr, "Resolving file %d...\n",n-0);
613 /* do use resolution */
614 if (!_nc_resolve_uses())
616 (void) fprintf(stderr,
617 "There are unresolved use entries in %s:\n",
622 (void) fputs(qp->tterm.term_names, stderr);
623 (void) fputc('\n', stderr);
628 heads[filecount] = _nc_head;
629 tails[filecount] = _nc_tail;
633 /* OK, all entries are in core. Ready to do the comparison */
635 (void) fprintf(stderr, "Entries are now in core...\n");
638 * The entry-matching loop. We're not using the use[]
639 * slots any more (they got zeroed out by resolve_uses) so
640 * we stash each entry's matches in the other file there.
641 * Sigh, this is intrinsically quadratic.
643 for (qp = heads[0]; qp; qp = qp->next)
645 for (rp = heads[1]; rp; rp = rp->next)
646 if (_nc_entry_match(qp->tterm.term_names,rp->tterm.term_names))
649 * This is why the uses structure parent element is
650 * (void *) -- so we can have either (char *) for
651 * names or entry structure pointers in them and still
654 if (qp->nuses < MAX_USES)
655 qp->uses[qp->nuses].parent = (void *)rp;
658 if (rp->nuses < MAX_USES)
659 rp->uses[rp->nuses].parent = (void *)qp;
664 /* now we have two circular lists with crosslinks */
666 (void) fprintf(stderr, "Name matches are done...\n");
668 for (qp = heads[0]; qp; qp = qp->next)
671 (void) fprintf(stderr,
672 "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
673 _nc_first_name(qp->tterm.term_names),
677 for (i = 0; i < qp->nuses; i++)
678 (void) fprintf(stderr,
680 _nc_first_name(((ENTRY *)qp->uses[i].parent)->tterm.term_names));
682 for (rp = heads[1]; rp; rp = rp->next)
685 (void) fprintf(stderr,
686 "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
687 _nc_first_name(rp->tterm.term_names),
691 for (i = 0; i < rp->nuses; i++)
692 (void) fprintf(stderr,
694 _nc_first_name(((ENTRY *)rp->uses[i].parent)->tterm.term_names));
697 (void) printf("In file 1 (%s) only:\n", argv[0]);
698 for (qp = heads[0]; qp; qp = qp->next)
700 (void) printf("\t%s\n",
701 _nc_first_name(qp->tterm.term_names));
703 (void) printf("In file 2 (%s) only:\n", argv[1]);
704 for (rp = heads[1]; rp; rp = rp->next)
706 (void) printf("\t%s\n",
707 _nc_first_name(rp->tterm.term_names));
709 (void) printf("The following entries are equivalent:\n");
710 for (qp = heads[0]; qp; qp = qp->next)
712 rp = (ENTRY *)qp->uses[0].parent;
714 if (qp->nuses == 1 && entryeq(&qp->tterm, &rp->tterm))
716 char name1[NAMESIZE], name2[NAMESIZE];
718 (void) canonical_name(qp->tterm.term_names, name1);
719 (void) canonical_name(rp->tterm.term_names, name2);
721 (void) printf("%s = %s\n", name1, name2);
725 (void) printf("Differing entries:\n");
727 for (qp = heads[0]; qp; qp = qp->next)
729 rp = (ENTRY *)qp->uses[0].parent;
731 if (qp->nuses == 1 && !entryeq(&qp->tterm, &rp->tterm))
733 char name1[NAMESIZE], name2[NAMESIZE];
735 memcpy(&term[0], &qp->tterm, sizeof(TERMTYPE));
736 memcpy(&term[1], &rp->tterm, sizeof(TERMTYPE));
738 (void) canonical_name(qp->tterm.term_names, name1);
739 (void) canonical_name(rp->tterm.term_names, name2);
745 (void)fprintf(stderr,"infocmp: dumping differences\n");
746 (void) printf("comparing %s to %s.\n", name1, name2);
747 compare_entry(compare_predicate);
752 (void) fprintf(stderr,
753 "infocmp: dumping common capabilities\n");
754 (void) printf("comparing %s to %s.\n", name1, name2);
755 compare_entry(compare_predicate);
760 (void) fprintf(stderr,
761 "infocmp: dumping differences\n");
762 (void) printf("comparing %s to %s.\n", name1, name2);
763 compare_entry(compare_predicate);
771 static void usage(void)
774 "usage: infocmp [-dcnILCuvV1T] [-s d| i| l| c] [-w width] [-A directory] [-B directory] [termname...]\n");
778 /***************************************************************************
782 ***************************************************************************/
784 int main(int argc, char *argv[])
786 char *terminal, *firstdir, *restdir;
787 path tfile[MAXTERMS];
789 bool filecompare = FALSE;
790 bool initdump = FALSE;
791 bool init_analyze = FALSE;
794 if ((terminal = getenv("TERM")) == NULL)
796 (void) fprintf(stderr,
797 "infocmp: environment variable TERM not set\n");
801 /* where is the terminfo database location going to default to? */
802 restdir = firstdir = 0;
804 while ((c = getopt(argc, argv, "decCFIinlLprR:s:uv:Vw:A:B:1T")) != EOF)
808 compare = C_DIFFERENCE;
822 if (sortmode == S_DEFAULT)
823 sortmode = S_TERMCAP;
835 outform = F_TERMINFO;
839 outform = F_VARIABLE;
840 if (sortmode == S_DEFAULT)
841 sortmode = S_VARIABLE;
853 tversion = (char *)NULL;
863 else if (*optarg == 'i')
864 sortmode = S_TERMINFO;
865 else if (*optarg == 'l')
866 sortmode = S_VARIABLE;
867 else if (*optarg == 'c')
868 sortmode = S_TERMCAP;
871 (void) fprintf(stderr,
872 "infocmp: unknown sort mode\n");
882 itrace = atoi(optarg);
883 _nc_tracing = (1 << itrace) - 1;
887 (void) fputs(NCURSES_VERSION, stdout);
889 ExitProgram(EXIT_SUCCESS);
892 mwidth = atoi(optarg);
913 /* by default, sort by terminfo name */
914 if (sortmode == S_DEFAULT)
915 sortmode = S_TERMINFO;
917 /* set up for display */
918 dump_init(tversion, outform, sortmode, mwidth, itrace);
920 /* make sure we have at least one terminal name to work with */
922 argv[argc++] = terminal;
924 /* if user is after a comparison, make sure we have two entries */
925 if (compare != C_DEFAULT && optind >= argc - 1)
926 argv[argc++] = terminal;
928 /* exactly two terminal names with no options means do -d */
929 if (argc - optind == 2 && compare == C_DEFAULT)
930 compare = C_DIFFERENCE;
934 /* grab the entries */
936 for (; optind < argc; optind++)
938 if (termcount >= MAXTERMS)
940 (void) fprintf(stderr,
941 "infocmp: too many terminal type arguments\n");
946 const char *directory = termcount ? restdir : firstdir;
949 tname[termcount] = argv[optind];
953 (void) sprintf(tfile[termcount], "%s/%c/%s",
955 *argv[optind], argv[optind]);
957 (void) fprintf(stderr,
958 "infocmp: reading entry %s from file %s\n",
959 argv[optind], tfile[termcount]);
961 status = _nc_read_file_entry(tfile[termcount],
967 (void) fprintf(stderr,
968 "infocmp: reading entry %s from system directories %s\n",
969 argv[optind], tname[termcount]);
971 status = _nc_read_entry(tname[termcount],
974 directory = TERMINFO; /* for error message */
979 (void) fprintf(stderr,
980 "infocmp: couldn't open terminfo file %s.\n",
988 /* dump as C initializer for the terminal type */
995 (void) printf("\t%s\n\t\t\"%s\",\n",
996 L_CURL, term->term_names);
997 (void) printf("\t\t(char *)0,\n");
999 (void) printf("\t\t%s /* BOOLEANS */\n", L_CURL);
1000 for (n = 0; n < BOOLCOUNT; n++)
1002 switch((int)(term->Booleans[n]))
1012 case ABSENT_BOOLEAN:
1013 str = "ABSENT_BOOLEAN";
1016 case CANCELLED_BOOLEAN:
1017 str = "CANCELLED_BOOLEAN";
1020 (void) printf("\t\t/* %s */\t%s%s,\n",
1022 n == BOOLCOUNT-1 ? R_CURL : "");
1025 (void) printf("\t\t%s /* NUMERICS */\n", L_CURL);
1026 for (n = 0; n < NUMCOUNT; n++)
1029 switch (term->Numbers[n])
1031 case ABSENT_NUMERIC:
1032 str = "ABSENT_NUMERIC";
1034 case CANCELLED_NUMERIC:
1035 str = "CANCELLED_NUMERIC";
1038 sprintf(buf, "%d", term->Numbers[n]);
1042 (void) printf("\t\t/* %s */\t%s%s,\n",
1044 n == NUMCOUNT-1 ? R_CURL : "");
1047 size = sizeof(TERMTYPE)
1048 + (BOOLCOUNT * sizeof(term->Booleans[0]))
1049 + (NUMCOUNT * sizeof(term->Numbers[0]));
1051 (void) printf("\t\t%s /* STRINGS */\n", L_CURL);
1052 for (n = 0; n < STRCOUNT; n++)
1054 char buf[BUFSIZ], *sp, *tp;
1056 if (term->Strings[n] == ABSENT_STRING)
1057 str = "ABSENT_STRING";
1058 else if (term->Strings[n] == CANCELLED_STRING)
1059 str = "CANCELLED_STRING";
1064 for (sp = term->Strings[n]; *sp; sp++)
1065 if (isascii(*sp) && isprint(*sp) && *sp !='\\' && *sp != '"')
1069 (void) sprintf(tp, "\\%03o", *sp);
1074 size += (strlen(term->Strings[n]) + 1);
1077 (void) printf("\t\t/* %s */\t%s%s%s\n",
1079 n == STRCOUNT-1 ? R_CURL : "",
1080 n == STRCOUNT-1 ? "" : ",");
1082 (void) printf("\t%s /* size = %d */\n", R_CURL, size);
1083 ExitProgram(EXIT_SUCCESS);
1086 /* analyze the init strings */
1090 #define CUR term[0].
1091 analyze_string("is1", init_1string, &term[0]);
1092 analyze_string("is2", init_2string, &term[0]);
1093 analyze_string("is3", init_3string, &term[0]);
1094 analyze_string("rs1", reset_1string, &term[0]);
1095 analyze_string("rs2", reset_2string, &term[0]);
1096 analyze_string("rs3", reset_3string, &term[0]);
1097 analyze_string("smcup", enter_ca_mode, &term[0]);
1098 analyze_string("rmcup", exit_ca_mode, &term[0]);
1100 ExitProgram(EXIT_SUCCESS);
1104 * Here's where the real work gets done
1110 (void) fprintf(stderr,
1111 "infocmp: about to dump %s\n",
1113 (void) printf("#\tReconstructed via infocmp from file: %s\n",
1115 len = dump_entry(&term[0], limited, NULL);
1118 (void)fprintf(stderr,"infocmp: length %d\n", len);
1123 (void)fprintf(stderr,"infocmp: dumping differences\n");
1124 (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1125 compare_entry(compare_predicate);
1130 (void) fprintf(stderr,
1131 "infocmp: dumping common capabilities\n");
1132 (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1133 compare_entry(compare_predicate);
1138 (void) fprintf(stderr,
1139 "infocmp: dumping differences\n");
1140 (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1141 compare_entry(compare_predicate);
1146 (void) fprintf(stderr, "infocmp: dumping use entry\n");
1147 len = dump_entry(&term[0], limited, use_predicate);
1148 for (i = 1; i < termcount; i++)
1149 len += dump_uses(tname[i], !(outform==F_TERMCAP || outform==F_TCONVERR));
1152 (void)fprintf(stderr,"infocmp: length %d\n", len);
1156 else if (compare == C_USEALL)
1157 (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
1158 else if (compare == C_DEFAULT)
1159 (void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
1160 else if (argc - optind != 2)
1161 (void) fprintf(stderr,
1162 "File comparison needs exactly two file arguments.\n");
1164 file_comparison(argc-optind, argv+optind);
1166 ExitProgram(EXIT_SUCCESS);
1169 /* infocmp.c ends here */