1 /****************************************************************************
2 * Copyright (c) 1998 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
31 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
32 ****************************************************************************/
36 * infocmp.c -- decompile an entry, or compare two entries
37 * written by Eric S. Raymond
40 #include <progs.priv.h>
42 #include <term_entry.h>
43 #include <dump_entry.h>
45 MODULE_ID("$Id: infocmp.c,v 1.34 1998/02/11 12:14:03 tom Exp $")
50 #define MAXTERMS 32 /* max # terminal arguments we can handle */
52 const char *_nc_progname = "infocmp";
54 typedef char path[PATH_MAX];
56 /***************************************************************************
58 * The following control variables, together with the contents of the
59 * terminfo entries, completely determine the actions of the program.
61 ***************************************************************************/
63 static char *tname[MAXTERMS]; /* terminal type names */
64 static TERMTYPE term[MAXTERMS]; /* terminfo entries */
65 static int termcount; /* count of terminal entries */
67 static const char *tversion; /* terminfo version selected */
68 static int outform; /* output format */
69 static int sortmode; /* sort_mode */
70 static int itrace; /* trace flag for debugging */
71 static int mwidth = 60;
73 /* main comparison mode */
75 #define C_DEFAULT 0 /* don't force comparison mode */
76 #define C_DIFFERENCE 1 /* list differences between two terminals */
77 #define C_COMMON 2 /* list common capabilities */
78 #define C_NAND 3 /* list capabilities in neither terminal */
79 #define C_USEALL 4 /* generate relative use-form entry */
80 static bool ignorepads; /* ignore pad prefixes when diffing */
84 static void ExitProgram(int code) GCC_NORETURN;
85 static void ExitProgram(int code)
87 while (termcount-- > 0)
88 _nc_free_termtype(&term[termcount], FALSE);
89 _nc_leaks_dump_entry();
90 _nc_free_and_exit(code);
94 static char *canonical_name(char *ptr, char *buf)
95 /* extract the terminal type's primary name */
99 (void) strcpy(buf, ptr);
100 if ((bp = strchr(buf, '|')) != (char *)NULL)
106 /***************************************************************************
108 * Predicates for dump function
110 ***************************************************************************/
112 static int capcmp(const char *s, const char *t)
113 /* capability comparison function */
115 if (!VALID_STRING(s) && !VALID_STRING(t))
117 else if (!VALID_STRING(s) || !VALID_STRING(t))
121 return(_nc_capcmp(s, t));
123 return(strcmp(s, t));
126 static int use_predicate(int type, int idx)
127 /* predicate function to use for use decompilation */
137 * This assumes that multiple use entries are supposed
138 * to contribute the logical or of their boolean capabilities.
139 * This is true if we take the semantics of multiple uses to
140 * be 'each capability gets the first non-default value found
141 * in the sequence of use entries'.
143 for (tp = &term[1]; tp < term + termcount; tp++)
144 if (tp->Booleans[idx]) {
148 if (is_set != term->Booleans[idx])
155 int value = ABSENT_NUMERIC;
158 * We take the semantics of multiple uses to be 'each
159 * capability gets the first non-default value found
160 * in the sequence of use entries'.
162 for (tp = &term[1]; tp < term + termcount; tp++)
163 if (tp->Numbers[idx] >= 0) {
164 value = tp->Numbers[idx];
168 if (value != term->Numbers[idx])
169 return(value != ABSENT_NUMERIC);
175 char *termstr, *usestr = ABSENT_STRING;
177 termstr = term->Strings[idx];
180 * We take the semantics of multiple uses to be 'each
181 * capability gets the first non-default value found
182 * in the sequence of use entries'.
184 for (tp = &term[1]; tp < term + termcount; tp++)
185 if (tp->Strings[idx])
187 usestr = tp->Strings[idx];
191 if (usestr == ABSENT_STRING && termstr == ABSENT_STRING)
193 else if (!usestr || !termstr || capcmp(usestr, termstr))
200 return(FALSE); /* pacify compiler */
203 static bool entryeq(TERMTYPE *t1, TERMTYPE *t2)
204 /* are two terminal types equal */
208 for (i = 0; i < BOOLCOUNT; i++)
209 if (t1->Booleans[i] != t2->Booleans[i])
212 for (i = 0; i < NUMCOUNT; i++)
213 if (t1->Numbers[i] != t2->Numbers[i])
216 for (i = 0; i < STRCOUNT; i++)
217 if (capcmp(t1->Strings[i], t2->Strings[i]))
223 static void compare_predicate(int type, int idx, const char *name)
224 /* predicate function to use for entry difference reports */
226 register TERMTYPE *t1 = &term[0];
227 register TERMTYPE *t2 = &term[1];
236 if (t1->Booleans[idx] != t2->Booleans[idx])
237 (void) printf("\t%s: %c:%c.\n",
239 t1->Booleans[idx] ? 'T' : 'F',
240 t2->Booleans[idx] ? 'T' : 'F');
244 if (t1->Booleans[idx] && t2->Booleans[idx])
245 (void) printf("\t%s= T.\n", name);
249 if (!t1->Booleans[idx] && !t2->Booleans[idx])
250 (void) printf("\t!%s.\n", name);
259 if (t1->Numbers[idx] != t2->Numbers[idx])
260 (void) printf("\t%s: %d:%d.\n",
261 name, t1->Numbers[idx], t2->Numbers[idx]);
265 if (t1->Numbers[idx]!=-1 && t2->Numbers[idx]!=-1
266 && t1->Numbers[idx] == t2->Numbers[idx])
267 (void) printf("\t%s= %d.\n", name, t1->Numbers[idx]);
271 if (t1->Numbers[idx]==-1 && t2->Numbers[idx] == -1)
272 (void) printf("\t!%s.\n", name);
278 s1 = t1->Strings[idx];
279 s2 = t2->Strings[idx];
285 char buf1[BUFSIZ], buf2[BUFSIZ];
287 if (s1 == (char *)NULL)
288 (void) strcpy(buf1, "NULL");
291 (void) strcpy(buf1, "'");
292 (void) strcat(buf1, _nc_tic_expand(s1, outform==F_TERMINFO));
293 (void) strcat(buf1, "'");
296 if (s2 == (char *)NULL)
297 (void) strcpy(buf2, "NULL");
300 (void) strcpy(buf2, "'");
301 (void) strcat(buf2, _nc_tic_expand(s2, outform==F_TERMINFO));
302 (void) strcat(buf2, "'");
305 (void) printf("\t%s: %s, %s.\n",
311 if (s1 && s2 && !capcmp(s1, s2))
312 (void) printf("\t%s= '%s'.\n", name, _nc_tic_expand(s1, outform==F_TERMINFO));
317 (void) printf("\t!%s.\n", name);
325 /***************************************************************************
327 * Init string analysis
329 ***************************************************************************/
331 typedef struct {const char *from; const char *to;} assoc;
333 static const assoc std_caps[] =
335 /* these are specified by X.364 and iBCS2 */
336 {"\033c", "RIS"}, /* full reset */
337 {"\0337", "SC"}, /* save cursor */
338 {"\0338", "RC"}, /* restore cursor */
339 {"\033[r", "RSR"}, /* not an X.364 mnemonic */
340 {"\033[m", "SGR0"}, /* not an X.364 mnemonic */
341 {"\033[2J", "ED2"}, /* clear page */
343 /* this group is specified by ISO 2022 */
344 {"\033(0", "ISO DEC G0"}, /* enable DEC graphics for G0 */
345 {"\033(A", "ISO UK G0"}, /* enable UK chars for G0 */
346 {"\033(B", "ISO US G0"}, /* enable US chars for G0 */
347 {"\033)0", "ISO DEC G1"}, /* enable DEC graphics for G1 */
348 {"\033)A", "ISO UK G1"}, /* enable UK chars for G1 */
349 {"\033)B", "ISO US G1"}, /* enable US chars for G1 */
351 /* these are DEC private modes widely supported by emulators */
352 {"\033=", "DECPAM"}, /* application keypad mode */
353 {"\033>", "DECPNM"}, /* normal keypad mode */
354 {"\033<", "DECANSI"}, /* enter ANSI mode */
356 { (char *)0, (char *)0}
359 static const assoc private_modes[] =
360 /* DEC \E[ ... [hl] modes recognized by many emulators */
362 {"1", "CKM"}, /* application cursor keys */
363 {"2", "ANM"}, /* set VT52 mode */
364 {"3", "COLM"}, /* 132-column mode */
365 {"4", "SCLM"}, /* smooth scroll */
366 {"5", "SCNM"}, /* reverse video mode */
367 {"6", "OM"}, /* origin mode */
368 {"7", "AWM"}, /* wraparound mode */
369 {"8", "ARM"}, /* auto-repeat mode */
370 {(char *)0, (char *)0}
373 static const assoc ecma_highlights[] =
374 /* recognize ECMA attribute sequences */
376 {"0", "NORMAL"}, /* normal */
377 {"1", "+BOLD"}, /* bold on */
378 {"2", "+DIM"}, /* dim on */
379 {"3", "+ITALIC"}, /* italic on */
380 {"4", "+UNDERLINE"}, /* underline on */
381 {"5", "+BLINK"}, /* blink on */
382 {"6", "+FASTBLINK"}, /* fastblink on */
383 {"7", "+REVERSE"}, /* reverse on */
384 {"8", "+INVISIBLE"}, /* invisible on */
385 {"9", "+DELETED"}, /* deleted on */
386 {"10", "MAIN-FONT"}, /* select primary font */
387 {"11", "ALT-FONT-1"}, /* select alternate font 1 */
388 {"12", "ALT-FONT-2"}, /* select alternate font 2 */
389 {"13", "ALT-FONT-3"}, /* select alternate font 3 */
390 {"14", "ALT-FONT-4"}, /* select alternate font 4 */
391 {"15", "ALT-FONT-5"}, /* select alternate font 5 */
392 {"16", "ALT-FONT-6"}, /* select alternate font 6 */
393 {"17", "ALT-FONT-7"}, /* select alternate font 7 */
394 {"18", "ALT-FONT-1"}, /* select alternate font 1 */
395 {"19", "ALT-FONT-1"}, /* select alternate font 1 */
396 {"20", "FRAKTUR"}, /* Fraktur font */
397 {"21", "DOUBLEUNDER"}, /* double underline */
398 {"22", "-DIM"}, /* dim off */
399 {"23", "-ITALIC"}, /* italic off */
400 {"24", "-UNDERLINE"}, /* underline off */
401 {"25", "-BLINK"}, /* blink off */
402 {"26", "-FASTBLINK"}, /* fastblink off */
403 {"27", "-REVERSE"}, /* reverse off */
404 {"28", "-INVISIBLE"}, /* invisible off */
405 {"29", "-DELETED"}, /* deleted off */
406 {(char *)0, (char *)0}
409 static void analyze_string(const char *name, const char *cap, TERMTYPE *tp)
411 char buf[MAX_TERMINFO_LENGTH];
412 char buf2[MAX_TERMINFO_LENGTH];
416 if (cap == ABSENT_STRING || cap == CANCELLED_STRING)
418 (void) printf("%s: ", name);
421 for (sp = cap; *sp; sp++)
425 const char *expansion = 0;
427 /* first, check other capabilities in this entry */
428 for (i = 0; i < STRCOUNT; i++)
430 char *cp = tp->Strings[i];
432 /* don't use soft-key capabilities */
433 if (strnames[i][0] == 'k' && strnames[i][0] == 'f')
437 if (cp != ABSENT_STRING && cp != CANCELLED_STRING && cp[0] && cp != cap)
440 (void) strncpy(buf2, sp, len);
443 if (_nc_capcmp(cp, buf2))
446 #define ISRS(s) (!strncmp((s), "is", 2) || !strncmp((s), "rs", 2))
448 * Theoretically we just passed the test for translation
449 * (equality once the padding is stripped). However, there
450 * are a few more hoops that need to be jumped so that
451 * identical pairs of initialization and reset strings
452 * don't just refer to each other.
454 if (ISRS(name) || ISRS(strnames[i]))
459 expansion = strnames[i];
464 /* now check the standard capabilities */
466 for (ap = std_caps; ap->from; ap++)
468 len = strlen(ap->from);
470 if (strncmp(ap->from, sp, len) == 0)
477 /* now check for private-mode sequences */
479 && sp[0] == '\033' && sp[1] == '[' && sp[2] == '?'
480 && (len = strspn(sp + 3, "0123456789;"))
481 && ((sp[3 + len] == 'h') || (sp[3 + len] == 'l')))
483 char buf3[MAX_TERMINFO_LENGTH];
485 (void) strcpy(buf2, (sp[3 + len] == 'h') ? "DEC+" : "DEC-");
486 (void) strncpy(buf3, sp + 3, len);
490 ep = strtok(buf3, ";");
494 for (ap = private_modes; ap->from; ap++)
496 size_t tlen = strlen(ap->from);
498 if (strncmp(ap->from, ep, tlen) == 0)
500 (void) strcat(buf2, ap->to);
507 (void) strcat(buf2, ep);
508 (void) strcat(buf2, ";");
510 ((ep = strtok((char *)NULL, ";")));
511 buf2[strlen(buf2) - 1] = '\0';
515 /* now check for ECMA highlight sequences */
517 && sp[0] == '\033' && sp[1] == '['
518 && (len = strspn(sp + 2, "0123456789;"))
519 && sp[2 + len] == 'm')
521 char buf3[MAX_TERMINFO_LENGTH];
523 (void) strcpy(buf2, "SGR:");
524 (void) strncpy(buf3, sp + 2, len);
528 ep = strtok(buf3, ";");
532 for (ap = ecma_highlights; ap->from; ap++)
534 size_t tlen = strlen(ap->from);
536 if (strncmp(ap->from, ep, tlen) == 0)
538 (void) strcat(buf2, ap->to);
545 (void) strcat(buf2, ep);
546 (void) strcat(buf2, ";");
548 ((ep = strtok((char *)NULL, ";")));
550 buf2[strlen(buf2) - 1] = '\0';
553 /* now check for scroll region reset */
556 (void) sprintf(buf2, "\033[1;%dr", tp->Numbers[2]);
558 if (strncmp(buf2, sp, len) == 0)
562 /* now check for home-down */
565 (void) sprintf(buf2, "\033[%d;1H", tp->Numbers[2]);
567 if (strncmp(buf2, sp, len) == 0)
571 /* now look at the expansion we got, if any */
574 (void) sprintf(buf + strlen(buf), "{%s}", expansion);
580 /* couldn't match anything */
583 (void) strcat(buf, _nc_tic_expand(buf2, outform==F_TERMINFO));
586 (void) printf("%s\n", buf);
589 /***************************************************************************
593 ***************************************************************************/
595 static void file_comparison(int argc, char *argv[])
598 /* someday we may allow comparisons on more files */
600 ENTRY *heads[MAXCOMPARE];
601 ENTRY *tails[MAXCOMPARE];
605 dump_init((char *)NULL, F_LITERAL, S_TERMINFO, 0, itrace);
607 for (n = 0; n < argc && n < MAXCOMPARE; n++)
609 if (freopen(argv[n], "r", stdin) == NULL)
610 _nc_err_abort("Can't open %s", argv[n]);
612 _nc_head = _nc_tail = (ENTRY *)NULL;
614 /* parse entries out of the source file */
615 _nc_set_source(argv[n]);
616 _nc_read_entry_source(stdin, NULL, TRUE, FALSE, NULLHOOK);
619 (void) fprintf(stderr, "Resolving file %d...\n", n-0);
621 /* do use resolution */
622 if (!_nc_resolve_uses())
624 (void) fprintf(stderr,
625 "There are unresolved use entries in %s:\n",
630 (void) fputs(qp->tterm.term_names, stderr);
631 (void) fputc('\n', stderr);
636 heads[filecount] = _nc_head;
637 tails[filecount] = _nc_tail;
641 /* OK, all entries are in core. Ready to do the comparison */
643 (void) fprintf(stderr, "Entries are now in core...\n");
646 * The entry-matching loop. We're not using the use[]
647 * slots any more (they got zeroed out by resolve_uses) so
648 * we stash each entry's matches in the other file there.
649 * Sigh, this is intrinsically quadratic.
651 for (qp = heads[0]; qp; qp = qp->next)
653 for (rp = heads[1]; rp; rp = rp->next)
654 if (_nc_entry_match(qp->tterm.term_names, rp->tterm.term_names))
657 * This is why the uses structure parent element is
658 * (void *) -- so we can have either (char *) for
659 * names or entry structure pointers in them and still
662 if (qp->nuses < MAX_USES)
663 qp->uses[qp->nuses].parent = (void *)rp;
666 if (rp->nuses < MAX_USES)
667 rp->uses[rp->nuses].parent = (void *)qp;
672 /* now we have two circular lists with crosslinks */
674 (void) fprintf(stderr, "Name matches are done...\n");
676 for (qp = heads[0]; qp; qp = qp->next)
679 (void) fprintf(stderr,
680 "%s in file 1 (%s) has %d matches in file 2 (%s):\n",
681 _nc_first_name(qp->tterm.term_names),
685 for (i = 0; i < qp->nuses; i++)
686 (void) fprintf(stderr,
688 _nc_first_name(((ENTRY *)qp->uses[i].parent)->tterm.term_names));
690 for (rp = heads[1]; rp; rp = rp->next)
693 (void) fprintf(stderr,
694 "%s in file 2 (%s) has %d matches in file 1 (%s):\n",
695 _nc_first_name(rp->tterm.term_names),
699 for (i = 0; i < rp->nuses; i++)
700 (void) fprintf(stderr,
702 _nc_first_name(((ENTRY *)rp->uses[i].parent)->tterm.term_names));
705 (void) printf("In file 1 (%s) only:\n", argv[0]);
706 for (qp = heads[0]; qp; qp = qp->next)
708 (void) printf("\t%s\n",
709 _nc_first_name(qp->tterm.term_names));
711 (void) printf("In file 2 (%s) only:\n", argv[1]);
712 for (rp = heads[1]; rp; rp = rp->next)
714 (void) printf("\t%s\n",
715 _nc_first_name(rp->tterm.term_names));
717 (void) printf("The following entries are equivalent:\n");
718 for (qp = heads[0]; qp; qp = qp->next)
720 rp = (ENTRY *)qp->uses[0].parent;
722 if (qp->nuses == 1 && entryeq(&qp->tterm, &rp->tterm))
724 char name1[NAMESIZE], name2[NAMESIZE];
726 (void) canonical_name(qp->tterm.term_names, name1);
727 (void) canonical_name(rp->tterm.term_names, name2);
729 (void) printf("%s = %s\n", name1, name2);
733 (void) printf("Differing entries:\n");
735 for (qp = heads[0]; qp; qp = qp->next)
737 rp = (ENTRY *)qp->uses[0].parent;
739 if (qp->nuses == 1 && !entryeq(&qp->tterm, &rp->tterm))
741 char name1[NAMESIZE], name2[NAMESIZE];
743 memcpy(&term[0], &qp->tterm, sizeof(TERMTYPE));
744 memcpy(&term[1], &rp->tterm, sizeof(TERMTYPE));
746 (void) canonical_name(qp->tterm.term_names, name1);
747 (void) canonical_name(rp->tterm.term_names, name2);
753 (void)fprintf(stderr, "infocmp: dumping differences\n");
754 (void) printf("comparing %s to %s.\n", name1, name2);
755 compare_entry(compare_predicate);
760 (void) fprintf(stderr,
761 "infocmp: dumping common capabilities\n");
762 (void) printf("comparing %s to %s.\n", name1, name2);
763 compare_entry(compare_predicate);
768 (void) fprintf(stderr,
769 "infocmp: dumping differences\n");
770 (void) printf("comparing %s to %s.\n", name1, name2);
771 compare_entry(compare_predicate);
779 static void usage(void)
782 "usage: infocmp [-dcnILCuvV1T] [-s d| i| l| c] [-w width] [-A directory] [-B directory] [termname...]\n");
786 /***************************************************************************
790 ***************************************************************************/
792 int main(int argc, char *argv[])
794 char *terminal, *firstdir, *restdir;
795 /* Avoid "local data >32k" error with mwcc */
796 /* Also avoid overflowing smaller stacks on systems like AmigaOS */
797 path *tfile = malloc(sizeof(path)*MAXTERMS);
799 bool filecompare = FALSE;
800 bool initdump = FALSE;
801 bool init_analyze = FALSE;
804 if ((terminal = getenv("TERM")) == NULL)
806 (void) fprintf(stderr,
807 "infocmp: environment variable TERM not set\n");
811 /* where is the terminfo database location going to default to? */
812 restdir = firstdir = 0;
814 while ((c = getopt(argc, argv, "decCFIinlLprR:s:uv:Vw:A:B:1T")) != EOF)
818 compare = C_DIFFERENCE;
832 if (sortmode == S_DEFAULT)
833 sortmode = S_TERMCAP;
841 outform = F_TERMINFO;
842 if (sortmode == S_DEFAULT)
843 sortmode = S_VARIABLE;
852 outform = F_TERMINFO;
856 outform = F_VARIABLE;
857 if (sortmode == S_DEFAULT)
858 sortmode = S_VARIABLE;
880 else if (*optarg == 'i')
881 sortmode = S_TERMINFO;
882 else if (*optarg == 'l')
883 sortmode = S_VARIABLE;
884 else if (*optarg == 'c')
885 sortmode = S_TERMCAP;
888 (void) fprintf(stderr,
889 "infocmp: unknown sort mode\n");
899 itrace = atoi(optarg);
900 _nc_tracing = (1 << itrace) - 1;
904 (void) fputs(NCURSES_VERSION, stdout);
906 ExitProgram(EXIT_SUCCESS);
909 mwidth = atoi(optarg);
930 /* by default, sort by terminfo name */
931 if (sortmode == S_DEFAULT)
932 sortmode = S_TERMINFO;
934 /* set up for display */
935 dump_init(tversion, outform, sortmode, mwidth, itrace);
937 /* make sure we have at least one terminal name to work with */
939 argv[argc++] = terminal;
941 /* if user is after a comparison, make sure we have two entries */
942 if (compare != C_DEFAULT && optind >= argc - 1)
943 argv[argc++] = terminal;
945 /* exactly two terminal names with no options means do -d */
946 if (argc - optind == 2 && compare == C_DEFAULT)
947 compare = C_DIFFERENCE;
951 /* grab the entries */
953 for (; optind < argc; optind++)
955 if (termcount >= MAXTERMS)
957 (void) fprintf(stderr,
958 "infocmp: too many terminal type arguments\n");
963 const char *directory = termcount ? restdir : firstdir;
966 tname[termcount] = argv[optind];
970 (void) sprintf(tfile[termcount], "%s/%c/%s",
972 *argv[optind], argv[optind]);
974 (void) fprintf(stderr,
975 "infocmp: reading entry %s from file %s\n",
976 argv[optind], tfile[termcount]);
978 status = _nc_read_file_entry(tfile[termcount],
984 (void) fprintf(stderr,
985 "infocmp: reading entry %s from system directories %s\n",
986 argv[optind], tname[termcount]);
988 status = _nc_read_entry(tname[termcount],
991 directory = TERMINFO; /* for error message */
996 (void) fprintf(stderr,
997 "infocmp: couldn't open terminfo file %s.\n",
1005 /* dump as C initializer for the terminal type */
1009 const char *str = 0;
1012 (void) printf("\t%s\n\t\t\"%s\",\n",
1013 L_CURL, term->term_names);
1014 (void) printf("\t\t(char *)0,\n");
1016 (void) printf("\t\t%s /* BOOLEANS */\n", L_CURL);
1017 for (n = 0; n < BOOLCOUNT; n++)
1019 switch((int)(term->Booleans[n]))
1029 case ABSENT_BOOLEAN:
1030 str = "ABSENT_BOOLEAN";
1033 case CANCELLED_BOOLEAN:
1034 str = "CANCELLED_BOOLEAN";
1037 (void) printf("\t\t/* %s */\t%s%s,\n",
1039 n == BOOLCOUNT-1 ? R_CURL : "");
1042 (void) printf("\t\t%s /* NUMERICS */\n", L_CURL);
1043 for (n = 0; n < NUMCOUNT; n++)
1046 switch (term->Numbers[n])
1048 case ABSENT_NUMERIC:
1049 str = "ABSENT_NUMERIC";
1051 case CANCELLED_NUMERIC:
1052 str = "CANCELLED_NUMERIC";
1055 sprintf(buf, "%d", term->Numbers[n]);
1059 (void) printf("\t\t/* %s */\t%s%s,\n",
1061 n == NUMCOUNT-1 ? R_CURL : "");
1064 size = sizeof(TERMTYPE)
1065 + (BOOLCOUNT * sizeof(term->Booleans[0]))
1066 + (NUMCOUNT * sizeof(term->Numbers[0]));
1068 (void) printf("\t\t%s /* STRINGS */\n", L_CURL);
1069 for (n = 0; n < STRCOUNT; n++)
1071 char buf[BUFSIZ], *sp, *tp;
1073 if (term->Strings[n] == ABSENT_STRING)
1074 str = "ABSENT_STRING";
1075 else if (term->Strings[n] == CANCELLED_STRING)
1076 str = "CANCELLED_STRING";
1081 for (sp = term->Strings[n]; *sp; sp++)
1083 if (isascii(*sp) && isprint(*sp) && *sp !='\\' && *sp != '"')
1087 (void) sprintf(tp, "\\%03o", *sp & 0xff);
1093 size += (strlen(term->Strings[n]) + 1);
1096 (void) printf("\t\t/* %s */\t%s%s%s\n",
1098 n == STRCOUNT-1 ? R_CURL : "",
1099 n == STRCOUNT-1 ? "" : ",");
1101 (void) printf("\t%s /* size = %d */\n", R_CURL, size);
1102 ExitProgram(EXIT_SUCCESS);
1105 /* analyze the init strings */
1109 #define CUR term[0].
1110 analyze_string("is1", init_1string, &term[0]);
1111 analyze_string("is2", init_2string, &term[0]);
1112 analyze_string("is3", init_3string, &term[0]);
1113 analyze_string("rs1", reset_1string, &term[0]);
1114 analyze_string("rs2", reset_2string, &term[0]);
1115 analyze_string("rs3", reset_3string, &term[0]);
1116 analyze_string("smcup", enter_ca_mode, &term[0]);
1117 analyze_string("rmcup", exit_ca_mode, &term[0]);
1119 ExitProgram(EXIT_SUCCESS);
1123 * Here's where the real work gets done
1129 (void) fprintf(stderr,
1130 "infocmp: about to dump %s\n",
1132 (void) printf("#\tReconstructed via infocmp from file: %s\n",
1134 len = dump_entry(&term[0], limited, NULL);
1137 (void)fprintf(stderr, "infocmp: length %d\n", len);
1142 (void)fprintf(stderr, "infocmp: dumping differences\n");
1143 (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1144 compare_entry(compare_predicate);
1149 (void) fprintf(stderr,
1150 "infocmp: dumping common capabilities\n");
1151 (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1152 compare_entry(compare_predicate);
1157 (void) fprintf(stderr,
1158 "infocmp: dumping differences\n");
1159 (void) printf("comparing %s to %s.\n", tname[0], tname[1]);
1160 compare_entry(compare_predicate);
1165 (void) fprintf(stderr, "infocmp: dumping use entry\n");
1166 len = dump_entry(&term[0], limited, use_predicate);
1167 for (i = 1; i < termcount; i++)
1168 len += dump_uses(tname[i], !(outform==F_TERMCAP || outform==F_TCONVERR));
1171 (void)fprintf(stderr, "infocmp: length %d\n", len);
1175 else if (compare == C_USEALL)
1176 (void) fprintf(stderr, "Sorry, -u doesn't work with -F\n");
1177 else if (compare == C_DEFAULT)
1178 (void) fprintf(stderr, "Use `tic -[CI] <file>' for this.\n");
1179 else if (argc - optind != 2)
1180 (void) fprintf(stderr,
1181 "File comparison needs exactly two file arguments.\n");
1183 file_comparison(argc-optind, argv+optind);
1185 ExitProgram(EXIT_SUCCESS);
1188 /* infocmp.c ends here */