1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /* Copyright (c) 1988 AT&T */
23 /* All Rights Reserved */
24
25
26 /*
27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
29 *
30 * Copyright (c) 2019, Joyent, Inc.
31 */
32
33 /*
34 NAME
35 infocmp - compare terminfo descriptions, or dump a terminfo
36 description
37
38 AUTHOR
39 Tony Hansen, February 23, 1984.
40 */
41
42 #include "curses.h"
43 #include "term.h"
44 #include "print.h"
45 #include <fcntl.h>
46 #include <stdlib.h>
47
48 /* externs from libcurses */
49 extern char *boolnames[];
50 extern char *boolcodes[];
51 extern char *boolfnames[];
52 extern char *numnames[];
53 extern char *numcodes[];
54 extern char *numfnames[];
55 extern char *strnames[];
56 extern char *strcodes[];
57 extern char *strfnames[];
58 extern char ttytype[];
59 extern int tgetflag();
60 extern int tgetnum();
61 extern char *tgetstr();
62
63 /* externs from libc */
64 extern void exit();
65 extern void qsort();
66 extern char *getenv();
67 extern int getopt();
68 extern int optind;
69 extern char *optarg;
70 extern char *strncpy(), *strcpy();
71 extern int strcmp(), strlen();
72
73 /* data structures for this program */
74
75 struct boolstruct {
76 char *infoname; /* the terminfo capability name */
77 char *capname; /* the termcap capability name */
78 char *fullname; /* the long C variable name */
79 char *secondname; /* the use= terminal w/ this value */
80 char val; /* the value */
81 char secondval; /* the value in the use= terminal */
82 char changed; /* a use= terminal changed the value */
83 char seenagain; /* a use= terminal had this entry */
84 };
85
86 struct numstruct {
87 char *infoname; /* ditto from above */
88 char *capname;
89 char *fullname;
90 char *secondname;
91 short val;
92 short secondval;
93 char changed;
94 char seenagain;
95 };
96
97 struct strstruct {
98 char *infoname; /* ditto from above */
99 char *capname;
100 char *fullname;
101 char *secondname;
102 char *val;
103 char *secondval;
104 char changed;
105 char seenagain;
106 };
107
108 /* globals for this file */
109 char *progname; /* argv[0], the name of the program */
110 static struct boolstruct *ibool; /* array of char information */
111 static struct numstruct *num; /* array of number information */
112 static struct strstruct *str; /* array of string information */
113 static char *used; /* usage statistics */
114 static int numbools; /* how many booleans there are */
115 static int numnums; /* how many numbers there are */
116 static int numstrs; /* how many strings there are */
117 #define TTYLEN 255
118 static char *firstterm; /* the name of the first terminal */
119 static char *savettytype; /* the synonyms of the first terminal */
120 static char _savettytype[TTYLEN+1]; /* the place to save those names */
121 static int devnull; /* open("/dev/null") for setupterm */
122 #define trace stderr /* send trace messages to stderr */
123
124 /* options */
125 static int verbose = 0; /* debugging printing level */
126 static int diff = 0; /* produce diff listing, the default */
127 static int common = 0; /* produce common listing */
128 static int neither = 0; /* list caps in neither entry */
129 static int use = 0; /* produce use= comparison listing */
130 static enum printtypes printing /* doing any of above printing at all */
131 = pr_none;
132 enum { none, by_database, by_terminfo, by_longnames, by_cap }
133 sortorder = none; /* sort the fields for printing */
134 static char *term1info, *term2info; /* $TERMINFO settings */
135 static int Aflag = 0, Bflag = 0; /* $TERMINFO was set with -A/-B */
136
137 #define EQUAL(s1, s2) (((s1 == NULL) && (s2 == NULL)) || \
138 ((s1 != NULL) && (s2 != NULL) && \
139 (strcmp(s1, s2) == 0)))
140
141 static void sortnames();
142 int numcompare(const void *, const void *);
143 int boolcompare(const void *, const void *);
144 int strcompare(const void *, const void *);
145 static void check_nth_terminal(char *, int);
146
147 void
badmalloc()148 badmalloc()
149 {
150 (void) fprintf(stderr, "%s: malloc is out of space!\n", progname);
151 exit(-1);
152 }
153
154 /*
155 Allocate and initialize the global data structures and variables.
156 */
157 void
allocvariables(int argc,int firstoptind)158 allocvariables(int argc, int firstoptind)
159 {
160 register int i, nullseen;
161
162 /* find out how many names we are dealing with */
163 for (numbools = 0; boolnames[numbools]; numbools++)
164 ;
165 for (numnums = 0; numnames[numnums]; numnums++)
166 ;
167 for (numstrs = 0; strnames[numstrs]; numstrs++)
168 ;
169
170 if (verbose) {
171 (void) fprintf(trace, "There are %d boolean capabilities.\n",
172 numbools);
173 (void) fprintf(trace, "There are %d numeric capabilities.\n",
174 numnums);
175 (void) fprintf(trace, "There are %d string capabilities.\n",
176 numstrs);
177 }
178
179 /* Allocate storage for the names and their values */
180 ibool = (struct boolstruct *) malloc((unsigned) numbools *
181 sizeof (struct boolstruct));
182 num = (struct numstruct *) malloc((unsigned) numnums *
183 sizeof (struct numstruct));
184 str = (struct strstruct *) malloc((unsigned) numstrs *
185 sizeof (struct strstruct));
186
187 /* Allocate array to keep track of which names have been used. */
188 if (use) {
189 used = (char *) malloc((unsigned) (argc - firstoptind) *
190 sizeof (char));
191 }
192
193 if ((ibool == NULL) || (num == NULL) || (str == NULL) ||
194 (use && (used == NULL)))
195 badmalloc();
196
197 /* Fill in the names and initialize the structures. */
198 nullseen = FALSE;
199 for (i = 0; i < numbools; i++) {
200 ibool[i].infoname = boolnames[i];
201 ibool[i].capname = boolcodes[i];
202 /* This is necessary until fnames.c is */
203 /* incorporated into standard curses. */
204 if (nullseen || (boolfnames[i] == NULL)) {
205 ibool[i].fullname = "unknown_boolean";
206 nullseen = TRUE;
207 } else {
208 ibool[i].fullname = boolfnames[i];
209 }
210 ibool[i].changed = FALSE;
211 ibool[i].seenagain = FALSE;
212 }
213 nullseen = 0;
214 for (i = 0; i < numnums; i++) {
215 num[i].infoname = numnames[i];
216 num[i].capname = numcodes[i];
217 if (nullseen || (numfnames[i] == NULL)) {
218 ibool[i].fullname = "unknown_number";
219 nullseen = TRUE;
220 } else {
221 num[i].fullname = numfnames[i];
222 }
223 num[i].changed = FALSE;
224 num[i].seenagain = FALSE;
225 }
226 nullseen = 0;
227 for (i = 0; i < numstrs; i++) {
228 str[i].infoname = strnames[i];
229 str[i].capname = strcodes[i];
230 if (nullseen || (strfnames[i] == NULL)) {
231 str[i].fullname = "unknown_string";
232 nullseen = TRUE;
233 } else {
234 str[i].fullname = strfnames[i];
235 }
236 str[i].changed = FALSE;
237 str[i].seenagain = FALSE;
238 }
239 }
240
241 /*
242 Routines to be passed to qsort(3) for comparison of the structures.
243 */
244 int
boolcompare(const void * x,const void * y)245 boolcompare(const void *x, const void *y)
246 {
247 struct boolstruct *a;
248 struct boolstruct *b;
249
250 a = (struct boolstruct *)x;
251 b = (struct boolstruct *)y;
252
253 switch ((int) sortorder) {
254 case (int) by_terminfo:
255 return (strcmp(a->infoname, b->infoname));
256 case (int) by_cap:
257 return (strcmp(a->capname, b->capname));
258 case (int) by_longnames:
259 return (strcmp(a->fullname, b->fullname));
260 default:
261 return (0);
262 }
263 }
264
265 int
numcompare(const void * x,const void * y)266 numcompare(const void *x, const void *y)
267 {
268 struct numstruct *a;
269 struct numstruct *b;
270
271 a = (struct numstruct *)x;
272 b = (struct numstruct *)y;
273 switch ((int) sortorder) {
274 case (int) by_terminfo:
275 return (strcmp(a->infoname, b->infoname));
276 case (int) by_cap:
277 return (strcmp(a->capname, b->capname));
278 case (int) by_longnames:
279 return (strcmp(a->fullname, b->fullname));
280 default:
281 return (0);
282 }
283 }
284
285 int
strcompare(const void * x,const void * y)286 strcompare(const void *x, const void *y)
287 {
288 struct strstruct *a;
289 struct strstruct *b;
290
291 a = (struct strstruct *)x;
292 b = (struct strstruct *)y;
293
294 switch ((int) sortorder) {
295 case (int) by_terminfo:
296 return (strcmp(a->infoname, b->infoname));
297 case (int) by_cap:
298 return (strcmp(a->capname, b->capname));
299 case (int) by_longnames:
300 return (strcmp(a->fullname, b->fullname));
301 default:
302 return (0);
303 }
304 }
305
306 /*
307 Sort the entries by their terminfo name.
308 */
309 static void
sortnames()310 sortnames()
311 {
312 if (sortorder != by_database) {
313 qsort((char *) ibool, (unsigned) numbools,
314 sizeof (struct boolstruct), boolcompare);
315 qsort((char *) num, (unsigned) numnums,
316 sizeof (struct numstruct), numcompare);
317 qsort((char *) str, (unsigned) numstrs,
318 sizeof (struct strstruct), strcompare);
319 }
320 return;
321 }
322
323 /*
324 Print out a string, or "NULL" if it's not defined.
325 */
326 void
PR(FILE * stream,char * string)327 PR(FILE *stream, char *string)
328 {
329 if (string == NULL)
330 (void) fprintf(stream, "NULL");
331 else
332 tpr(stream, string);
333 }
334
335 /*
336 Output the 'ko' termcap string. This is a list of all of the input
337 keys that input the same thing as the corresponding output strings.
338 */
339 int kncounter;
340 char kobuffer[512];
341
342 char
addko(char * output,char * input,char * koptr)343 *addko(char *output, char *input, char *koptr)
344 {
345 char *inptr, *outptr, padbuffer[512];
346 inptr = tgetstr(input, (char **)0);
347 if (inptr == NULL)
348 return (koptr);
349 outptr = tgetstr(output, (char **)0);
350 if (outptr == NULL)
351 return (koptr);
352 outptr = rmpadding(outptr, padbuffer, (int *) 0);
353 if (strcmp(inptr, outptr) == 0) {
354 *koptr++ = *output++;
355 *koptr++ = *output++;
356 *koptr++ = ',';
357 kncounter++;
358 }
359 return (koptr);
360 }
361
362 void
setupknko()363 setupknko()
364 {
365 char *koptr;
366
367 kncounter = 0;
368 koptr = kobuffer;
369
370 koptr = addko("bs", "kb", koptr); /* key_backspace */
371 koptr = addko("bt", "kB", koptr); /* key_btab */
372 koptr = addko("cl", "kC", koptr); /* key_clear */
373 koptr = addko("le", "kl", koptr); /* key_left */
374 koptr = addko("do", "kd", koptr); /* key_down */
375 koptr = addko("nd", "kr", koptr); /* key_right */
376 koptr = addko("up", "ku", koptr); /* key_up */
377 koptr = addko("dc", "kD", koptr); /* key_dc */
378 koptr = addko("dl", "kL", koptr); /* key_dl */
379 koptr = addko("cd", "kS", koptr); /* key_eos */
380 koptr = addko("ce", "kE", koptr); /* key_eol */
381 koptr = addko("ho", "kh", koptr); /* key_home */
382 koptr = addko("st", "kT", koptr); /* key_stab */
383 koptr = addko("ic", "kI", koptr); /* key_ic */
384 koptr = addko("im", "kI", koptr); /* key_ic */
385 koptr = addko("al", "kA", koptr); /* key_il */
386 koptr = addko("sf", "kF", koptr); /* key_sf */
387 koptr = addko("ll", "kH", koptr); /* key_ll */
388 koptr = addko("sr", "kR", koptr); /* key_sr */
389 koptr = addko("ei", "kM", koptr); /* key_eic */
390 koptr = addko("ct", "ka", koptr); /* key_catab */
391
392 /* get rid of comma */
393 if (koptr != kobuffer)
394 *(--koptr) = '\0';
395 }
396
397 void
pr_kn()398 pr_kn()
399 {
400 if (kncounter > 0)
401 pr_number((char *)0, "kn", (char *)0, kncounter);
402 }
403
404 void
pr_ko()405 pr_ko()
406 {
407 if (kncounter > 0)
408 pr_string((char *)0, "ko", (char *)0, kobuffer);
409 }
410
411 void
pr_bcaps()412 pr_bcaps()
413 {
414 char *retptr;
415 char padbuffer[512];
416
417 if (verbose)
418 (void) fprintf(trace, "looking at 'bs'\n");
419 retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0));
420 if (strcmp("\\b", retptr) == 0)
421 pr_boolean((char *)0, "bs", (char *)0, 1);
422
423 if (verbose)
424 (void) fprintf(trace, "looking at 'pt'\n");
425 retptr = cconvert(rmpadding(tab, padbuffer, (int *) 0));
426 if (strcmp("\\t", retptr) == 0)
427 pr_boolean((char *)0, "pt", (char *)0, 1);
428
429 if (verbose)
430 (void) fprintf(trace, "looking at 'nc'\n");
431 retptr = cconvert(rmpadding(carriage_return, padbuffer, (int *) 0));
432 if (strcmp("\\r", retptr) != 0)
433 pr_boolean((char *)0, "nc", (char *)0, 1);
434
435 if (verbose)
436 (void) fprintf(trace, "looking at 'ns'\n");
437 if (scroll_forward == NULL)
438 pr_boolean((char *)0, "ns", (char *)0, 1);
439
440 /* Ignore "xr": Return acts like ce \r \n (Delta Data) */
441 }
442
443 void
pr_ncaps()444 pr_ncaps()
445 {
446 char padbuffer[512];
447 int padding;
448
449 if (verbose)
450 (void) fprintf(trace, "looking at 'ug'\n");
451 /* Duplicate sg for ug: Number of blank chars left by us or ue */
452 if (magic_cookie_glitch > -1)
453 pr_number((char *)0, "ug", (char *)0, magic_cookie_glitch);
454
455 if (verbose)
456 (void) fprintf(trace, "looking at 'dB'\n");
457 /* Number of millisec of bs delay needed */
458 (void) rmpadding(cursor_left, padbuffer, &padding);
459 if (padding > 0)
460 pr_number((char *)0, "dB", (char *)0, padding);
461
462 if (verbose)
463 (void) fprintf(trace, "looking at 'dC'\n");
464 /* Number of millisec of cr delay needed */
465 (void) rmpadding(carriage_return, padbuffer, &padding);
466 if (padding > 0)
467 pr_number((char *)0, "dC", (char *)0, padding);
468
469 if (verbose)
470 (void) fprintf(trace, "looking at 'dF'\n");
471 /* Number of millisec of ff delay needed */
472 (void) rmpadding(form_feed, padbuffer, &padding);
473 if (padding > 0)
474 pr_number((char *)0, "dF", (char *)0, padding);
475
476 if (verbose)
477 (void) fprintf(trace, "looking at 'dN'\n");
478 /* Number of millisec of nl delay needed */
479 (void) rmpadding(cursor_down, padbuffer, &padding);
480 if (padding > 0)
481 pr_number((char *)0, "dN", (char *)0, padding);
482
483 if (verbose)
484 (void) fprintf(trace, "looking at 'dT'\n");
485 /* Number of millisec of tab delay needed */
486 (void) rmpadding(tab, padbuffer, &padding);
487 if (padding > 0)
488 pr_number((char *)0, "dT", (char *)0, padding);
489
490 /* Handle "kn": Number of "other" keys */
491 setupknko();
492 pr_kn();
493 }
494
495 void
pr_scaps()496 pr_scaps()
497 {
498 char *retptr;
499 char padbuffer[512];
500
501 /* Backspace if not "^H" */
502 if (verbose)
503 (void) fprintf(trace, "looking at 'bc'\n");
504 retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0));
505 if (strcmp("\\b", retptr) != 0)
506 pr_string((char *)0, "bc", (char *)0, cursor_left);
507
508 /* Newline character (default "\n") */
509 if (verbose)
510 (void) fprintf(trace, "looking at 'nl'\n");
511 retptr = cconvert(rmpadding(cursor_down, padbuffer, (int *) 0));
512 if (strcmp("\\n", retptr) != 0)
513 pr_string((char *)0, "nl", (char *)0, cursor_down);
514
515 /* Handle "ko" here: Termcap entries for other non-function keys */
516 pr_ko();
517
518 /* Ignore "ma": Arrow key map, used by vi version 2 only */
519 }
520
521 /*
522 Set up the first terminal and save the values from it.
523 */
524 void
initfirstterm(char * term)525 initfirstterm(char *term)
526 {
527 register int i;
528
529 if (verbose) {
530 (void) fprintf(trace, "setting up terminal type '%s'.\n",
531 term);
532 }
533
534 (void) setupterm(term, devnull, (int *) 0);
535
536 /* Save the name for later use. */
537 if (use) {
538 register unsigned int length;
539 savettytype = _savettytype;
540 if ((length = strlen(ttytype)) >= TTYLEN) {
541 savettytype = malloc(length);
542 if (savettytype == NULL) {
543 (void) fprintf(stderr, "%s: malloc is out "
544 "of space\n", progname);
545 (void) strncpy(_savettytype, ttytype,
546 TTYLEN-1);
547 _savettytype[TTYLEN] = '\0';
548 savettytype = _savettytype;
549 }
550 } else {
551 (void) strcpy(_savettytype, ttytype);
552 }
553 }
554
555 if (printing != pr_none) {
556 pr_heading(term, ttytype);
557 pr_bheading();
558 }
559
560 /* Save the values for the first terminal. */
561 for (i = 0; i < numbools; i++) {
562 if ((ibool[i].val = tgetflag(ibool[i].capname)) &&
563 printing != pr_none) {
564 pr_boolean(ibool[i].infoname, ibool[i].capname,
565 ibool[i].fullname, 1);
566 }
567
568 if (verbose) {
569 (void) fprintf(trace, "%s=%d.\n", ibool[i].infoname,
570 ibool[i].val);
571 }
572 }
573
574 if (printing != pr_none) {
575 if (printing == pr_cap)
576 pr_bcaps();
577 pr_bfooting();
578 pr_nheading();
579 }
580
581 for (i = 0; i < numnums; i++) {
582 if (((num[i].val = tgetnum(num[i].capname)) > -1) &&
583 printing != pr_none) {
584 pr_number(num[i].infoname, num[i].capname,
585 num[i].fullname, num[i].val);
586 }
587
588 if (verbose) {
589 (void) fprintf(trace, "%s=%d.\n", num[i].infoname,
590 num[i].val);
591 }
592 }
593
594 if (printing != pr_none) {
595 if (printing == pr_cap)
596 pr_ncaps();
597 pr_nfooting();
598 pr_sheading();
599 }
600
601 for (i = 0; i < numstrs; i++) {
602 str[i].val = tgetstr(str[i].capname, (char **)0);
603 if ((str[i].val != NULL) && printing != pr_none) {
604 pr_string(str[i].infoname, str[i].capname,
605 str[i].fullname, str[i].val);
606 }
607
608 if (verbose) {
609 (void) fprintf(trace, "%s='", str[i].infoname);
610 PR(trace, str[i].val);
611 (void) fprintf(trace, "'.\n");
612 }
613 }
614
615 if (printing == pr_cap)
616 pr_scaps();
617
618 if (printing != pr_none)
619 pr_sfooting();
620 }
621
622 /*
623 Set up the n'th terminal.
624 */
625 static void
check_nth_terminal(char * nterm,int n)626 check_nth_terminal(char *nterm, int n)
627 {
628 register char boolval;
629 register short numval;
630 register char *strval;
631 register int i;
632
633 if (use)
634 used[n] = FALSE;
635
636 if (verbose) {
637 (void) fprintf(trace, "adding in terminal type '%s'.\n",
638 nterm);
639 }
640
641 (void) setupterm(nterm, devnull, (int *) 0);
642
643 if (printing != pr_none) {
644 pr_heading(nterm, ttytype);
645 pr_bheading();
646 }
647
648 if (diff || common || neither) {
649 if (Aflag && Bflag)
650 (void) printf("comparing %s (TERMINFO=%s) to %s "
651 "(TERMINFO=%s).\n",
652 firstterm, term1info, nterm, term2info);
653 else if (Aflag)
654 (void) printf("comparing %s (TERMINFO=%s) to %s.\n",
655 firstterm, term1info, nterm);
656 else if (Bflag)
657 (void) printf("comparing %s to %s (TERMINFO=%s).\n",
658 firstterm, nterm, term2info);
659 else
660 (void) printf("comparing %s to %s.\n",
661 firstterm, nterm);
662 (void) printf(" comparing booleans.\n");
663 }
664
665 /* save away the values for the nth terminal */
666 for (i = 0; i < numbools; i++) {
667 boolval = tgetflag(ibool[i].capname);
668 if (use) {
669 if (ibool[i].seenagain) {
670 /*
671 ** We do not have to worry about this impossible case
672 ** since booleans can have only two values: true and
673 ** false.
674 ** if (boolval && (boolval != ibool[i].secondval))
675 ** {
676 ** (void) fprintf(trace, "use= order dependency"
677 ** "found:\n");
678 ** (void) fprintf(trace, " %s: %s has %d, %s has"
679 ** " %d.\n",
680 ** ibool[i].capname, ibool[i].secondname,
681 ** ibool[i].secondval, nterm, boolval);
682 ** }
683 */
684 } else {
685 if (boolval == TRUE) {
686 ibool[i].seenagain = TRUE;
687 ibool[i].secondval = boolval;
688 ibool[i].secondname = nterm;
689 if (ibool[i].val != boolval)
690 ibool[i].changed = TRUE;
691 else
692 used[n] = TRUE;
693 }
694 }
695 }
696 if (boolval) {
697 if (printing != pr_none) {
698 pr_boolean(ibool[i].infoname, ibool[i].capname,
699 ibool[i].fullname, 1);
700 }
701
702 if (common && (ibool[i].val == boolval))
703 (void) printf("\t%s= T.\n", ibool[i].infoname);
704 } else if (neither && !ibool[i].val) {
705 (void) printf("\t!%s.\n", ibool[i].infoname);
706 }
707 if (diff && (ibool[i].val != boolval))
708 (void) printf("\t%s: %c:%c.\n", ibool[i].infoname,
709 ibool[i].val?'T':'F', boolval?'T':'F');
710 if (verbose) {
711 (void) fprintf(trace, "%s: %d:%d, changed=%d, "
712 "seen=%d.\n", ibool[i].infoname, ibool[i].val,
713 boolval, ibool[i].changed, ibool[i].seenagain);
714 }
715 }
716
717 if (printing != pr_none) {
718 if (printing == pr_cap)
719 pr_bcaps();
720 pr_bfooting();
721 pr_nheading();
722 }
723
724 if (diff || common || neither)
725 (void) printf(" comparing numbers.\n");
726
727 for (i = 0; i < numnums; i++) {
728 numval = tgetnum(num[i].capname);
729 if (use) {
730 if (num[i].seenagain) {
731 if ((numval > -1) &&
732 (numval != num[i].secondval)) {
733 (void) fprintf(stderr,
734 "%s: use = order dependency "
735 "found:\n", progname);
736 (void) fprintf(stderr, " %s: %s "
737 "has %d, %s has %d.\n",
738 num[i].capname, num[i].secondname,
739 num[i].secondval, nterm, numval);
740 }
741 } else {
742 if (numval > -1) {
743 num[i].seenagain = TRUE;
744 num[i].secondval = numval;
745 num[i].secondname = nterm;
746 if ((numval > -1) &&
747 (num[i].val != numval))
748 num[i].changed = TRUE;
749 else
750 used[n] = TRUE;
751 }
752 }
753 }
754 if (numval > -1) {
755 if (printing != pr_none) {
756 pr_number(num[i].infoname, num[i].capname,
757 num[i].fullname, numval);
758 }
759
760 if (common && (num[i].val == numval)) {
761 (void) printf("\t%s= %d.\n", num[i].infoname,
762 numval);
763 }
764
765 } else if (neither && (num[i].val == -1)) {
766 (void) printf("\t!%s.\n", num[i].infoname);
767 }
768
769 if (diff && (num[i].val != numval)) {
770 (void) printf("\t%s: %d:%d.\n",
771 num[i].infoname, num[i].val, numval);
772 }
773
774 if (verbose) {
775 (void) fprintf(trace, "%s: %d:%d, "
776 "changed = %d, seen = %d.\n",
777 num[i].infoname, num[i].val, numval,
778 num[i].changed, num[i].seenagain);
779 }
780 }
781
782 if (printing != pr_none) {
783 if (printing == pr_cap)
784 pr_ncaps();
785 pr_nfooting();
786 pr_sheading();
787 }
788
789 if (diff || common || neither)
790 (void) printf(" comparing strings.\n");
791
792 for (i = 0; i < numstrs; i++) {
793 strval = tgetstr(str[i].capname, (char **)0);
794 if (use) {
795 if (str[i].seenagain && (strval != NULL)) {
796 if (!EQUAL(strval, str[i].secondval)) {
797 (void) fprintf(stderr,
798 "use= order dependency"
799 " found:\n");
800 (void) fprintf(stderr,
801 " %s: %s has '",
802 str[i].capname, str[i].secondname);
803 PR(stderr, str[i].secondval);
804 (void) fprintf(stderr,
805 "', %s has '", nterm);
806 PR(stderr, strval);
807 (void) fprintf(stderr, "'.\n");
808 }
809 } else {
810 if (strval != NULL) {
811 str[i].seenagain = TRUE;
812 str[i].secondval = strval;
813 str[i].secondname = nterm;
814 if (!EQUAL(str[i].val, strval))
815 str[i].changed = TRUE;
816 else
817 used[n] = TRUE;
818 }
819 }
820 }
821 if (strval != NULL) {
822 if (printing != pr_none) {
823 pr_string(str[i].infoname, str[i].capname,
824 str[i].fullname, strval);
825 }
826
827 if (common && EQUAL(str[i].val, strval)) {
828 (void) printf("\t%s= '", str[i].infoname);
829 PR(stdout, strval);
830 (void) printf("'.\n");
831 }
832 } else if (neither && (str[i].val == NULL))
833 (void) printf("\t!%s.\n", str[i].infoname);
834 if (diff && !EQUAL(str[i].val, strval)) {
835 (void) printf("\t%s: '", str[i].infoname);
836 PR(stdout, str[i].val);
837 (void) printf("','");
838 PR(stdout, strval);
839 (void) printf("'.\n");
840 }
841 if (verbose) {
842 (void) fprintf(trace, "%s: '", str[i].infoname);
843 PR(trace, str[i].val);
844 (void) fprintf(trace, "':'");
845 PR(trace, strval);
846 (void) fprintf(trace, "',changed=%d,seen=%d.\n",
847 str[i].changed, str[i].seenagain);
848 }
849 }
850
851 if (printing == pr_cap)
852 pr_scaps();
853
854 if (printing != pr_none)
855 pr_sfooting();
856
857 return;
858 }
859
860 /*
861 A capability gets an at-sign if it no longer exists, but
862 one of the relative entries contains a value for it.
863 It gets printed if the original value is not seen in ANY
864 of the relative entries, or if the FIRST relative entry that has
865 the capability gives a DIFFERENT value for the capability.
866 */
867 void
dorelative(int firstoptind,int argc,char ** argv)868 dorelative(int firstoptind, int argc, char **argv)
869 {
870 register int i;
871
872 /* turn off printing of termcap and long names */
873 pr_init(pr_terminfo);
874
875 /* print out the entry name */
876 pr_heading((char *)0, savettytype);
877
878 pr_bheading();
879
880 /* Print out all bools that are different. */
881 for (i = 0; i < numbools; i++) {
882 if (!ibool[i].val && ibool[i].changed) {
883 pr_boolean(ibool[i].infoname, (char *)0,
884 (char *)0, -1);
885 } else if (ibool[i].val && (ibool[i].changed ||
886 !ibool[i].seenagain)) {
887 pr_boolean(ibool[i].infoname, (char *)0, (char *)0, 1);
888 }
889 }
890
891 pr_bfooting();
892 pr_nheading();
893
894 /* Print out all nums that are different. */
895 for (i = 0; i < numnums; i++) {
896 if (num[i].val < 0 && num[i].changed) {
897 pr_number(num[i].infoname, (char *)0, (char *)0, -1);
898 } else if (num[i].val >= 0 && (num[i].changed ||
899 !num[i].seenagain)) {
900 pr_number(num[i].infoname, (char *)0,
901 (char *)0, num[i].val);
902 }
903 }
904
905 pr_nfooting();
906 pr_sheading();
907
908 /* Print out all strs that are different. */
909 for (i = 0; i < numstrs; i++) {
910 if (str[i].val == NULL && str[i].changed) {
911 pr_string(str[i].infoname, (char *)0, (char *)0,
912 (char *)0);
913 } else if ((str[i].val != NULL) &&
914 (str[i].changed || !str[i].seenagain)) {
915 pr_string(str[i].infoname,
916 (char *)0, (char *)0, str[i].val);
917 }
918 }
919
920 pr_sfooting();
921
922 /* Finish it up. */
923 for (i = firstoptind; i < argc; i++) {
924 if (used[i - firstoptind]) {
925 (void) printf("\tuse=%s,\n", argv[i]);
926 } else {
927 (void) fprintf(stderr,
928 "%s: 'use=%s' did not add anything to the "
929 "description.\n", progname, argv[i]);
930 }
931 }
932 }
933
934 void
local_setenv(char * termNinfo)935 local_setenv(char *termNinfo)
936 {
937 extern char **environ;
938 static char *newenviron[2] = { 0, 0 };
939 static unsigned int termsize = BUFSIZ;
940 static char _terminfo[BUFSIZ];
941 static char *terminfo = &_terminfo[0];
942 register int termlen;
943
944 if (termNinfo && *termNinfo) {
945 if (verbose) {
946 (void) fprintf(trace, "setting TERMINFO=%s.\n",
947 termNinfo);
948 }
949
950 termlen = strlen(termNinfo);
951 if (termlen + 10 > termsize) {
952 termsize = termlen + 20;
953 terminfo = (char *) malloc(termsize * sizeof (char));
954 }
955 if (terminfo == (char *) NULL)
956 badmalloc();
957 (void) sprintf(terminfo, "TERMINFO=%s", termNinfo);
958 newenviron[0] = terminfo;
959 } else
960 newenviron[0] = (char *) 0;
961 environ = newenviron;
962 }
963
964 int
main(int argc,char ** argv)965 main(int argc, char **argv)
966 {
967 int i, c, firstoptind;
968 char *tempargv[2];
969 char *term = getenv("TERM");
970
971 term1info = term2info = getenv("TERMINFO");
972 progname = argv[0];
973
974 /* parse options */
975 while ((c = getopt(argc, argv, "ducnILCvV1rw:s:A:B:")) != EOF)
976 switch (c) {
977 case 'v': verbose++;
978 break;
979 case '1': pr_onecolumn(1);
980 break;
981 case 'w': pr_width(atoi(optarg));
982 break;
983 case 'd': diff++;
984 break;
985 case 'c': common++;
986 break;
987 case 'n': neither++;
988 break;
989 case 'u': use++;
990 break;
991 case 'L': pr_init(printing = pr_longnames);
992 break;
993 case 'I': pr_init(printing = pr_terminfo);
994 break;
995 case 'C': pr_init(printing = pr_cap);
996 break;
997 case 'A': term1info = optarg; Aflag++;
998 break;
999 case 'B': term2info = optarg; Bflag++;
1000 break;
1001 case 'r': pr_caprestrict(0);
1002 break;
1003 case 's':
1004 if (strcmp(optarg, "d") == 0)
1005 sortorder = by_database;
1006 else if (strcmp(optarg, "i") == 0)
1007 sortorder = by_terminfo;
1008 else if (strcmp(optarg, "l") == 0)
1009 sortorder = by_longnames;
1010 else if (strcmp(optarg, "c") == 0)
1011 sortorder = by_cap;
1012 else
1013 goto usage;
1014 break;
1015 case 'V':
1016 (void) printf("%s: version %s\n", progname,
1017 "@(#)curses:screen/infocmp.c 1.13");
1018 exit(0);
1019 case '?':
1020 usage:
1021 (void) fprintf(stderr,
1022 "usage: %s [-ducn] [-ILC] [-1Vv] "
1023 "[-s d|i|l|c] [-A directory] "
1024 "[-B directory] term-names ...\n",
1025 progname);
1026 (void) fprintf(stderr, "\t-d\tprint "
1027 "differences (the default for >1 "
1028 "term-name)\n");
1029 (void) fprintf(stderr, "\t-u\tproduce "
1030 "relative description\n");
1031 (void) fprintf(stderr, "\t-c\tprint common "
1032 "entries\n");
1033 (void) fprintf(stderr, "\t-n\tprint entries "
1034 "in neither\n");
1035 (void) fprintf(stderr, "\t-I\tprint terminfo "
1036 "entries (the default for 1 term-name)\n");
1037 (void) fprintf(stderr, "\t-C\tprint termcap "
1038 "entries\n");
1039 (void) fprintf(stderr, "\t-L\tprint long C "
1040 "variable names\n");
1041 (void) fprintf(stderr, "\t-1\tsingle column "
1042 "output\n");
1043 (void) fprintf(stderr, "\t-V\tprint program "
1044 "version\n");
1045 (void) fprintf(stderr, "\t-v\tverbose "
1046 "debugging output\n");
1047 (void) fprintf(stderr, "\t-s\tchange sort "
1048 "order\n");
1049 (void) fprintf(stderr, "\t-A\tset $TERMINFO "
1050 "for first term-name\n");
1051 (void) fprintf(stderr, "\t-B\tset $TERMINFO "
1052 "for other term-names\n");
1053 exit(-1);
1054 }
1055
1056 argc -= optind;
1057 argv += optind;
1058 optind = 0;
1059
1060 /* Default to $TERM for -n, -I, -C and -L options. */
1061 /* This is done by faking argv[][], argc and optind. */
1062 if (neither && (argc == 0 || argc == 1)) {
1063 if (argc == 0)
1064 tempargv[0] = term;
1065 else
1066 tempargv[0] = argv[optind];
1067 tempargv[1] = term;
1068 argc = 2;
1069 argv = tempargv;
1070 optind = 0;
1071 } else if ((printing != pr_none) && (argc == 0)) {
1072 tempargv[0] = term;
1073 argc = 1;
1074 argv = tempargv;
1075 optind = 0;
1076 }
1077
1078 /* Check for enough names. */
1079 if ((use || diff || common) && (argc <= 1)) {
1080 (void) fprintf(stderr,
1081 "%s: must have at least two terminal names for a "
1082 "comparison to be done.\n", progname);
1083 goto usage;
1084 }
1085
1086 /* Set the default of diff -d or print -I */
1087 if (!use && (printing == pr_none) && !common && !neither) {
1088 if (argc == 0 || argc == 1) {
1089 if (argc == 0) {
1090 tempargv[0] = term;
1091 argc = 1;
1092 argv = tempargv;
1093 optind = 0;
1094 }
1095 pr_init(printing = pr_terminfo);
1096 } else {
1097 diff++;
1098 }
1099 }
1100
1101 /* Set the default sorting order. */
1102 if (sortorder == none) {
1103 switch ((int) printing) {
1104 case (int) pr_cap:
1105 sortorder = by_cap; break;
1106 case (int) pr_longnames:
1107 sortorder = by_longnames; break;
1108 case (int) pr_terminfo:
1109 case (int) pr_none:
1110 sortorder = by_terminfo; break;
1111 }
1112 }
1113
1114 firstterm = argv[optind++];
1115 firstoptind = optind;
1116
1117 allocvariables(argc, firstoptind);
1118 sortnames();
1119
1120 devnull = open("/dev/null", O_RDWR);
1121 local_setenv(term1info);
1122 initfirstterm(firstterm);
1123 local_setenv(term2info);
1124 for (i = 0; optind < argc; optind++, i++)
1125 check_nth_terminal(argv[optind], i);
1126
1127 if (use)
1128 dorelative(firstoptind, argc, argv);
1129
1130 return (0);
1131 }
1132