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
31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13 */
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 if ((ibool == NULL) || (num == NULL) || (str == NULL) ||
193 (use && (used == NULL)))
194 badmalloc();
195
196 /* Fill in the names and initialize the structures. */
197 nullseen = FALSE;
198 for (i = 0; i < numbools; i++) {
199 ibool[i].infoname = boolnames[i];
200 ibool[i].capname = boolcodes[i];
201 /* This is necessary until fnames.c is */
202 /* incorporated into standard curses. */
203 if (nullseen || (boolfnames[i] == NULL)) {
204 ibool[i].fullname = "unknown_boolean";
205 nullseen = TRUE;
206 } else
207 ibool[i].fullname = boolfnames[i];
208 ibool[i].changed = FALSE;
209 ibool[i].seenagain = FALSE;
210 }
211 nullseen = 0;
212 for (i = 0; i < numnums; i++) {
213 num[i].infoname = numnames[i];
214 num[i].capname = numcodes[i];
215 if (nullseen || (numfnames[i] == NULL)) {
216 ibool[i].fullname = "unknown_number";
217 nullseen = TRUE;
218 } else
219 num[i].fullname = numfnames[i];
220 num[i].changed = FALSE;
221 num[i].seenagain = FALSE;
222 }
223 nullseen = 0;
224 for (i = 0; i < numstrs; i++) {
225 str[i].infoname = strnames[i];
226 str[i].capname = strcodes[i];
227 if (nullseen || (strfnames[i] == NULL)) {
228 str[i].fullname = "unknown_string";
229 nullseen = TRUE;
230 } else
231 str[i].fullname = strfnames[i];
232 str[i].changed = FALSE;
233 str[i].seenagain = FALSE;
234 }
235 }
236
237 /*
238 Routines to be passed to qsort(3) for comparison of the structures.
239 */
240 int
boolcompare(const void * x,const void * y)241 boolcompare(const void *x, const void *y)
242 {
243 struct boolstruct *a;
244 struct boolstruct *b;
245
246 a = (struct boolstruct *)x;
247 b = (struct boolstruct *)y;
248
249 switch ((int) sortorder) {
250 case (int) by_terminfo:
251 return (strcmp(a->infoname, b->infoname));
252 case (int) by_cap:
253 return (strcmp(a->capname, b->capname));
254 case (int) by_longnames:
255 return (strcmp(a->fullname, b->fullname));
256 default:
257 return (0);
258 }
259 }
260
261 int
numcompare(const void * x,const void * y)262 numcompare(const void *x, const void *y)
263 {
264 struct numstruct *a;
265 struct numstruct *b;
266
267 a = (struct numstruct *)x;
268 b = (struct numstruct *)y;
269 switch ((int) sortorder) {
270 case (int) by_terminfo:
271 return (strcmp(a->infoname, b->infoname));
272 case (int) by_cap:
273 return (strcmp(a->capname, b->capname));
274 case (int) by_longnames:
275 return (strcmp(a->fullname, b->fullname));
276 default:
277 return (0);
278 }
279 }
280
281 int
strcompare(const void * x,const void * y)282 strcompare(const void *x, const void *y)
283 {
284 struct strstruct *a;
285 struct strstruct *b;
286
287 a = (struct strstruct *)x;
288 b = (struct strstruct *)y;
289
290 switch ((int) sortorder) {
291 case (int) by_terminfo:
292 return (strcmp(a->infoname, b->infoname));
293 case (int) by_cap:
294 return (strcmp(a->capname, b->capname));
295 case (int) by_longnames:
296 return (strcmp(a->fullname, b->fullname));
297 default:
298 return (0);
299 }
300 }
301
302 /*
303 Sort the entries by their terminfo name.
304 */
305 static void
sortnames()306 sortnames()
307 {
308 if (sortorder != by_database) {
309 qsort((char *) ibool, (unsigned) numbools,
310 sizeof (struct boolstruct), boolcompare);
311 qsort((char *) num, (unsigned) numnums,
312 sizeof (struct numstruct), numcompare);
313 qsort((char *) str, (unsigned) numstrs,
314 sizeof (struct strstruct), strcompare);
315 }
316 return;
317 }
318
319 /*
320 Print out a string, or "NULL" if it's not defined.
321 */
322 void
PR(FILE * stream,char * string)323 PR(FILE *stream, char *string)
324 {
325 if (string == NULL)
326 (void) fprintf(stream, "NULL");
327 else
328 tpr(stream, string);
329 }
330
331 /*
332 Output the 'ko' termcap string. This is a list of all of the input
333 keys that input the same thing as the corresponding output strings.
334 */
335 int kncounter;
336 char kobuffer[512];
337
338 char
addko(char * output,char * input,char * koptr)339 *addko(char *output, char *input, char *koptr)
340 {
341 char *inptr, *outptr, padbuffer[512];
342 inptr = tgetstr(input, (char **)0);
343 if (inptr == NULL)
344 return (koptr);
345 outptr = tgetstr(output, (char **)0);
346 if (outptr == NULL)
347 return (koptr);
348 outptr = rmpadding(outptr, padbuffer, (int *) 0);
349 if (strcmp(inptr, outptr) == 0) {
350 *koptr++ = *output++;
351 *koptr++ = *output++;
352 *koptr++ = ',';
353 kncounter++;
354 }
355 return (koptr);
356 }
357
358 void
setupknko()359 setupknko()
360 {
361 char *koptr;
362
363 kncounter = 0;
364 koptr = kobuffer;
365
366 koptr = addko("bs", "kb", koptr); /* key_backspace */
367 koptr = addko("bt", "kB", koptr); /* key_btab */
368 koptr = addko("cl", "kC", koptr); /* key_clear */
369 koptr = addko("le", "kl", koptr); /* key_left */
370 koptr = addko("do", "kd", koptr); /* key_down */
371 koptr = addko("nd", "kr", koptr); /* key_right */
372 koptr = addko("up", "ku", koptr); /* key_up */
373 koptr = addko("dc", "kD", koptr); /* key_dc */
374 koptr = addko("dl", "kL", koptr); /* key_dl */
375 koptr = addko("cd", "kS", koptr); /* key_eos */
376 koptr = addko("ce", "kE", koptr); /* key_eol */
377 koptr = addko("ho", "kh", koptr); /* key_home */
378 koptr = addko("st", "kT", koptr); /* key_stab */
379 koptr = addko("ic", "kI", koptr); /* key_ic */
380 koptr = addko("im", "kI", koptr); /* key_ic */
381 koptr = addko("al", "kA", koptr); /* key_il */
382 koptr = addko("sf", "kF", koptr); /* key_sf */
383 koptr = addko("ll", "kH", koptr); /* key_ll */
384 koptr = addko("sr", "kR", koptr); /* key_sr */
385 koptr = addko("ei", "kM", koptr); /* key_eic */
386 koptr = addko("ct", "ka", koptr); /* key_catab */
387
388 /* get rid of comma */
389 if (koptr != kobuffer)
390 *(--koptr) = '\0';
391 }
392
393 void
pr_kn()394 pr_kn()
395 {
396 if (kncounter > 0)
397 pr_number((char *)0, "kn", (char *)0, kncounter);
398 }
399
400 void
pr_ko()401 pr_ko()
402 {
403 if (kncounter > 0)
404 pr_string((char *)0, "ko", (char *)0, kobuffer);
405 }
406
407 void
pr_bcaps()408 pr_bcaps()
409 {
410 char *retptr;
411 char padbuffer[512];
412
413 if (verbose)
414 (void) fprintf(trace, "looking at 'bs'\n");
415 retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0));
416 if (strcmp("\\b", retptr) == 0)
417 pr_boolean((char *)0, "bs", (char *)0, 1);
418
419 if (verbose)
420 (void) fprintf(trace, "looking at 'pt'\n");
421 retptr = cconvert(rmpadding(tab, padbuffer, (int *) 0));
422 if (strcmp("\\t", retptr) == 0)
423 pr_boolean((char *)0, "pt", (char *)0, 1);
424
425 if (verbose)
426 (void) fprintf(trace, "looking at 'nc'\n");
427 retptr = cconvert(rmpadding(carriage_return, padbuffer, (int *) 0));
428 if (strcmp("\\r", retptr) != 0)
429 pr_boolean((char *)0, "nc", (char *)0, 1);
430
431 if (verbose)
432 (void) fprintf(trace, "looking at 'ns'\n");
433 if (scroll_forward == NULL)
434 pr_boolean((char *)0, "ns", (char *)0, 1);
435
436 /* Ignore "xr": Return acts like ce \r \n (Delta Data) */
437 }
438
439 void
pr_ncaps()440 pr_ncaps()
441 {
442 char padbuffer[512];
443 int padding;
444
445 if (verbose)
446 (void) fprintf(trace, "looking at 'ug'\n");
447 /* Duplicate sg for ug: Number of blank chars left by us or ue */
448 if (magic_cookie_glitch > -1)
449 pr_number((char *)0, "ug", (char *)0, magic_cookie_glitch);
450
451 if (verbose)
452 (void) fprintf(trace, "looking at 'dB'\n");
453 /* Number of millisec of bs delay needed */
454 (void) rmpadding(cursor_left, padbuffer, &padding);
455 if (padding > 0)
456 pr_number((char *)0, "dB", (char *)0, padding);
457
458 if (verbose)
459 (void) fprintf(trace, "looking at 'dC'\n");
460 /* Number of millisec of cr delay needed */
461 (void) rmpadding(carriage_return, padbuffer, &padding);
462 if (padding > 0)
463 pr_number((char *)0, "dC", (char *)0, padding);
464
465 if (verbose)
466 (void) fprintf(trace, "looking at 'dF'\n");
467 /* Number of millisec of ff delay needed */
468 (void) rmpadding(form_feed, padbuffer, &padding);
469 if (padding > 0)
470 pr_number((char *)0, "dF", (char *)0, padding);
471
472 if (verbose)
473 (void) fprintf(trace, "looking at 'dN'\n");
474 /* Number of millisec of nl delay needed */
475 (void) rmpadding(cursor_down, padbuffer, &padding);
476 if (padding > 0)
477 pr_number((char *)0, "dN", (char *)0, padding);
478
479 if (verbose)
480 (void) fprintf(trace, "looking at 'dT'\n");
481 /* Number of millisec of tab delay needed */
482 (void) rmpadding(tab, padbuffer, &padding);
483 if (padding > 0)
484 pr_number((char *)0, "dT", (char *)0, padding);
485
486 /* Handle "kn": Number of "other" keys */
487 setupknko();
488 pr_kn();
489 }
490
491 void
pr_scaps()492 pr_scaps()
493 {
494 char *retptr;
495 char padbuffer[512];
496
497 /* Backspace if not "^H" */
498 if (verbose)
499 (void) fprintf(trace, "looking at 'bc'\n");
500 retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0));
501 if (strcmp("\\b", retptr) != 0)
502 pr_string((char *)0, "bc", (char *)0, cursor_left);
503
504 /* Newline character (default "\n") */
505 if (verbose)
506 (void) fprintf(trace, "looking at 'nl'\n");
507 retptr = cconvert(rmpadding(cursor_down, padbuffer, (int *) 0));
508 if (strcmp("\\n", retptr) != 0)
509 pr_string((char *)0, "nl", (char *)0, cursor_down);
510
511 /* Handle "ko" here: Termcap entries for other non-function keys */
512 pr_ko();
513
514 /* Ignore "ma": Arrow key map, used by vi version 2 only */
515 }
516
517 /*
518 Set up the first terminal and save the values from it.
519 */
520 void
initfirstterm(char * term)521 initfirstterm(char *term)
522 {
523 register int i;
524
525 if (verbose)
526 (void) fprintf(trace, "setting up terminal type '%s'.\n",
527 term);
528
529 (void) setupterm(term, devnull, (int *) 0);
530
531 /* Save the name for later use. */
532 if (use) {
533 register unsigned int length;
534 savettytype = _savettytype;
535 if ((length = strlen(ttytype)) >= TTYLEN) {
536 savettytype = malloc(length);
537 if (savettytype == NULL) {
538 (void) fprintf(stderr, "%s: malloc is out "
539 "of space\n", progname);
540 (void) strncpy(_savettytype, ttytype,
541 TTYLEN-1);
542 _savettytype[TTYLEN] = '\0';
543 savettytype = _savettytype;
544 }
545 } else
546 (void) strcpy(_savettytype, ttytype);
547 }
548
549 if (printing != pr_none) {
550 pr_heading(term, ttytype);
551 pr_bheading();
552 }
553
554 /* Save the values for the first terminal. */
555 for (i = 0; i < numbools; i++) {
556 if ((ibool[i].val = tgetflag(ibool[i].capname)) &&
557 printing != pr_none)
558 pr_boolean(ibool[i].infoname, ibool[i].capname,
559 ibool[i].fullname, 1);
560 if (verbose)
561 (void) fprintf(trace, "%s=%d.\n", ibool[i].infoname,
562 ibool[i].val);
563 }
564
565 if (printing != pr_none) {
566 if (printing == pr_cap)
567 pr_bcaps();
568 pr_bfooting();
569 pr_nheading();
570 }
571
572 for (i = 0; i < numnums; i++) {
573 if (((num[i].val = tgetnum(num[i].capname)) > -1) &&
574 printing != pr_none)
575 pr_number(num[i].infoname, num[i].capname,
576 num[i].fullname, num[i].val);
577 if (verbose)
578 (void) fprintf(trace, "%s=%d.\n", num[i].infoname,
579 num[i].val);
580 }
581
582 if (printing != pr_none) {
583 if (printing == pr_cap)
584 pr_ncaps();
585 pr_nfooting();
586 pr_sheading();
587 }
588
589 for (i = 0; i < numstrs; i++) {
590 str[i].val = tgetstr(str[i].capname, (char **)0);
591 if ((str[i].val != NULL) && printing != pr_none)
592 pr_string(str[i].infoname, str[i].capname,
593 str[i].fullname, str[i].val);
594 if (verbose) {
595 (void) fprintf(trace, "%s='", str[i].infoname);
596 PR(trace, str[i].val);
597 (void) fprintf(trace, "'.\n");
598 }
599 }
600
601 if (printing == pr_cap)
602 pr_scaps();
603
604 if (printing != pr_none)
605 pr_sfooting();
606 }
607
608 /*
609 Set up the n'th terminal.
610 */
611 static void
check_nth_terminal(char * nterm,int n)612 check_nth_terminal(char *nterm, int n)
613 {
614 register char boolval;
615 register short numval;
616 register char *strval;
617 register int i;
618
619 if (use)
620 used[n] = FALSE;
621
622 if (verbose)
623 (void) fprintf(trace, "adding in terminal type '%s'.\n",
624 nterm);
625
626 (void) setupterm(nterm, devnull, (int *) 0);
627
628 if (printing != pr_none) {
629 pr_heading(nterm, ttytype);
630 pr_bheading();
631 }
632
633 if (diff || common || neither) {
634 if (Aflag && Bflag)
635 (void) printf("comparing %s (TERMINFO=%s) to %s "
636 "(TERMINFO=%s).\n",
637 firstterm, term1info, nterm, term2info);
638 else if (Aflag)
639 (void) printf("comparing %s (TERMINFO=%s) to %s.\n",
640 firstterm, term1info, nterm);
641 else if (Bflag)
642 (void) printf("comparing %s to %s (TERMINFO=%s).\n",
643 firstterm, nterm, term2info);
644 else
645 (void) printf("comparing %s to %s.\n",
646 firstterm, nterm);
647 (void) printf(" comparing booleans.\n");
648 }
649
650 /* save away the values for the nth terminal */
651 for (i = 0; i < numbools; i++) {
652 boolval = tgetflag(ibool[i].capname);
653 if (use) {
654 if (ibool[i].seenagain) {
655 /*
656 ** We do not have to worry about this impossible case
657 ** since booleans can have only two values: true and
658 ** false.
659 ** if (boolval && (boolval != ibool[i].secondval))
660 ** {
661 ** (void) fprintf(trace, "use= order dependency"
662 ** "found:\n");
663 ** (void) fprintf(trace, " %s: %s has %d, %s has"
664 ** " %d.\n",
665 ** ibool[i].capname, ibool[i].secondname,
666 ** ibool[i].secondval, nterm, boolval);
667 ** }
668 */
669 } else {
670 if (boolval == TRUE) {
671 ibool[i].seenagain = TRUE;
672 ibool[i].secondval = boolval;
673 ibool[i].secondname = nterm;
674 if (ibool[i].val != boolval)
675 ibool[i].changed = TRUE;
676 else
677 used[n] = TRUE;
678 }
679 }
680 }
681 if (boolval) {
682 if (printing != pr_none)
683 pr_boolean(ibool[i].infoname, ibool[i].capname,
684 ibool[i].fullname, 1);
685 if (common && (ibool[i].val == boolval))
686 (void) printf("\t%s= T.\n", ibool[i].infoname);
687 } else if (neither && !ibool[i].val)
688 (void) printf("\t!%s.\n", ibool[i].infoname);
689 if (diff && (ibool[i].val != boolval))
690 (void) printf("\t%s: %c:%c.\n", ibool[i].infoname,
691 ibool[i].val?'T':'F', boolval?'T':'F');
692 if (verbose)
693 (void) fprintf(trace, "%s: %d:%d, changed=%d, "
694 "seen=%d.\n", ibool[i].infoname, ibool[i].val,
695 boolval, ibool[i].changed, ibool[i].seenagain);
696 }
697
698 if (printing != pr_none) {
699 if (printing == pr_cap)
700 pr_bcaps();
701 pr_bfooting();
702 pr_nheading();
703 }
704
705 if (diff || common || neither)
706 (void) printf(" comparing numbers.\n");
707
708 for (i = 0; i < numnums; i++) {
709 numval = tgetnum(num[i].capname);
710 if (use) {
711 if (num[i].seenagain) {
712 if ((numval > -1) &&
713 (numval != num[i].secondval)) {
714 (void) fprintf(stderr,
715 "%s: use = order dependency "
716 "found:\n", progname);
717 (void) fprintf(stderr, " %s: %s "
718 "has %d, %s has %d.\n",
719 num[i].capname, num[i].secondname,
720 num[i].secondval, nterm, numval);
721 }
722 } else {
723 if (numval > -1) {
724 num[i].seenagain = TRUE;
725 num[i].secondval = numval;
726 num[i].secondname = nterm;
727 if ((numval > -1) &&
728 (num[i].val != numval))
729 num[i].changed = TRUE;
730 else
731 used[n] = TRUE;
732 }
733 }
734 }
735 if (numval > -1) {
736 if (printing != pr_none)
737 pr_number(num[i].infoname, num[i].capname,
738 num[i].fullname, numval);
739 if (common && (num[i].val == numval))
740 (void) printf("\t%s= %d.\n", num[i].infoname,
741 numval);
742 } else if (neither && (num[i].val == -1))
743 (void) printf("\t!%s.\n", num[i].infoname);
744 if (diff && (num[i].val != numval))
745 (void) printf("\t%s: %d:%d.\n",
746 num[i].infoname, num[i].val, numval);
747 if (verbose)
748 (void) fprintf(trace, "%s: %d:%d, "
749 "changed = %d, seen = %d.\n",
750 num[i].infoname, num[i].val, numval,
751 num[i].changed, num[i].seenagain);
752 }
753
754 if (printing != pr_none) {
755 if (printing == pr_cap)
756 pr_ncaps();
757 pr_nfooting();
758 pr_sheading();
759 }
760
761 if (diff || common || neither)
762 (void) printf(" comparing strings.\n");
763
764 for (i = 0; i < numstrs; i++) {
765 strval = tgetstr(str[i].capname, (char **)0);
766 if (use) {
767 if (str[i].seenagain && (strval != NULL)) {
768 if (!EQUAL(strval, str[i].secondval)) {
769 (void) fprintf(stderr,
770 "use= order dependency"
771 " found:\n");
772 (void) fprintf(stderr,
773 " %s: %s has '",
774 str[i].capname, str[i].secondname);
775 PR(stderr, str[i].secondval);
776 (void) fprintf(stderr,
777 "', %s has '", nterm);
778 PR(stderr, strval);
779 (void) fprintf(stderr, "'.\n");
780 }
781 } else {
782 if (strval != NULL) {
783 str[i].seenagain = TRUE;
784 str[i].secondval = strval;
785 str[i].secondname = nterm;
786 if (!EQUAL(str[i].val, strval))
787 str[i].changed = TRUE;
788 else
789 used[n] = TRUE;
790 }
791 }
792 }
793 if (strval != NULL) {
794 if (printing != pr_none)
795 pr_string(str[i].infoname, str[i].capname,
796 str[i].fullname, strval);
797 if (common && EQUAL(str[i].val, strval)) {
798 (void) printf("\t%s= '", str[i].infoname);
799 PR(stdout, strval);
800 (void) printf("'.\n");
801 }
802 } else if (neither && (str[i].val == NULL))
803 (void) printf("\t!%s.\n", str[i].infoname);
804 if (diff && !EQUAL(str[i].val, strval)) {
805 (void) printf("\t%s: '", str[i].infoname);
806 PR(stdout, str[i].val);
807 (void) printf("','");
808 PR(stdout, strval);
809 (void) printf("'.\n");
810 }
811 if (verbose) {
812 (void) fprintf(trace, "%s: '", str[i].infoname);
813 PR(trace, str[i].val);
814 (void) fprintf(trace, "':'");
815 PR(trace, strval);
816 (void) fprintf(trace, "',changed=%d,seen=%d.\n",
817 str[i].changed, str[i].seenagain);
818 }
819 }
820
821 if (printing == pr_cap)
822 pr_scaps();
823
824 if (printing != pr_none)
825 pr_sfooting();
826
827 return;
828 }
829
830 /*
831 A capability gets an at-sign if it no longer exists, but
832 one of the relative entries contains a value for it.
833 It gets printed if the original value is not seen in ANY
834 of the relative entries, or if the FIRST relative entry that has
835 the capability gives a DIFFERENT value for the capability.
836 */
837 void
dorelative(int firstoptind,int argc,char ** argv)838 dorelative(int firstoptind, int argc, char **argv)
839 {
840 register int i;
841
842 /* turn off printing of termcap and long names */
843 pr_init(pr_terminfo);
844
845 /* print out the entry name */
846 pr_heading((char *)0, savettytype);
847
848 pr_bheading();
849
850 /* Print out all bools that are different. */
851 for (i = 0; i < numbools; i++)
852 if (!ibool[i].val && ibool[i].changed)
853 pr_boolean(ibool[i].infoname, (char *)0,
854 (char *)0, -1);
855 else if (ibool[i].val && (ibool[i].changed ||
856 !ibool[i].seenagain))
857 pr_boolean(ibool[i].infoname, (char *)0, (char *)0, 1);
858
859 pr_bfooting();
860 pr_nheading();
861
862 /* Print out all nums that are different. */
863 for (i = 0; i < numnums; i++)
864 if (num[i].val < 0 && num[i].changed)
865 pr_number(num[i].infoname, (char *)0, (char *)0, -1);
866 else if (num[i].val >= 0 && (num[i].changed ||
867 !num[i].seenagain))
868 pr_number(num[i].infoname, (char *)0,
869 (char *)0, num[i].val);
870
871 pr_nfooting();
872 pr_sheading();
873
874 /* Print out all strs that are different. */
875 for (i = 0; i < numstrs; i++)
876 if (str[i].val == NULL && str[i].changed)
877 pr_string(str[i].infoname, (char *)0, (char *)0,
878 (char *)0);
879 else if ((str[i].val != NULL) &&
880 (str[i].changed || !str[i].seenagain))
881 pr_string(str[i].infoname, (char *)0, (char *)0, str[i].val);
882
883 pr_sfooting();
884
885 /* Finish it up. */
886 for (i = firstoptind; i < argc; i++)
887 if (used[i - firstoptind])
888 (void) printf("\tuse=%s,\n", argv[i]);
889 else
890 (void) fprintf(stderr,
891 "%s: 'use=%s' did not add anything to the "
892 "description.\n", progname, argv[i]);
893 }
894
895 void
local_setenv(char * termNinfo)896 local_setenv(char *termNinfo)
897 {
898 extern char **environ;
899 static char *newenviron[2] = { 0, 0 };
900 static unsigned int termsize = BUFSIZ;
901 static char _terminfo[BUFSIZ];
902 static char *terminfo = &_terminfo[0];
903 register int termlen;
904
905 if (termNinfo && *termNinfo) {
906 if (verbose)
907 (void) fprintf(trace, "setting TERMINFO=%s.\n",
908 termNinfo);
909 termlen = strlen(termNinfo);
910 if (termlen + 10 > termsize) {
911 termsize = termlen + 20;
912 terminfo = (char *) malloc(termsize * sizeof (char));
913 }
914 if (terminfo == (char *) NULL)
915 badmalloc();
916 (void) sprintf(terminfo, "TERMINFO=%s", termNinfo);
917 newenviron[0] = terminfo;
918 } else
919 newenviron[0] = (char *) 0;
920 environ = newenviron;
921 }
922
923 int
main(int argc,char ** argv)924 main(int argc, char **argv)
925 {
926 int i, c, firstoptind;
927 char *tempargv[2];
928 char *term = getenv("TERM");
929
930 term1info = term2info = getenv("TERMINFO");
931 progname = argv[0];
932
933 /* parse options */
934 while ((c = getopt(argc, argv, "ducnILCvV1rw:s:A:B:")) != EOF)
935 switch (c) {
936 case 'v': verbose++;
937 break;
938 case '1': pr_onecolumn(1);
939 break;
940 case 'w': pr_width(atoi(optarg));
941 break;
942 case 'd': diff++;
943 break;
944 case 'c': common++;
945 break;
946 case 'n': neither++;
947 break;
948 case 'u': use++;
949 break;
950 case 'L': pr_init(printing = pr_longnames);
951 break;
952 case 'I': pr_init(printing = pr_terminfo);
953 break;
954 case 'C': pr_init(printing = pr_cap);
955 break;
956 case 'A': term1info = optarg; Aflag++;
957 break;
958 case 'B': term2info = optarg; Bflag++;
959 break;
960 case 'r': pr_caprestrict(0);
961 break;
962 case 's':
963 if (strcmp(optarg, "d") == 0)
964 sortorder = by_database;
965 else if (strcmp(optarg, "i") == 0)
966 sortorder = by_terminfo;
967 else if (strcmp(optarg, "l") == 0)
968 sortorder = by_longnames;
969 else if (strcmp(optarg, "c") == 0)
970 sortorder = by_cap;
971 else
972 goto usage;
973 break;
974 case 'V':
975 (void) printf("%s: version %s\n", progname,
976 "@(#)curses:screen/infocmp.c 1.13");
977 exit(0);
978 case '?':
979 usage:
980 (void) fprintf(stderr,
981 "usage: %s [-ducn] [-ILC] [-1Vv] "
982 "[-s d|i|l|c] [-A directory] "
983 "[-B directory] term-names ...\n",
984 progname);
985 (void) fprintf(stderr, "\t-d\tprint "
986 "differences (the default for >1 "
987 "term-name)\n");
988 (void) fprintf(stderr, "\t-u\tproduce "
989 "relative description\n");
990 (void) fprintf(stderr, "\t-c\tprint common "
991 "entries\n");
992 (void) fprintf(stderr, "\t-n\tprint entries "
993 "in neither\n");
994 (void) fprintf(stderr, "\t-I\tprint terminfo "
995 "entries (the default for 1 term-name)\n");
996 (void) fprintf(stderr, "\t-C\tprint termcap "
997 "entries\n");
998 (void) fprintf(stderr, "\t-L\tprint long C "
999 "variable names\n");
1000 (void) fprintf(stderr, "\t-1\tsingle column "
1001 "output\n");
1002 (void) fprintf(stderr, "\t-V\tprint program "
1003 "version\n");
1004 (void) fprintf(stderr, "\t-v\tverbose "
1005 "debugging output\n");
1006 (void) fprintf(stderr, "\t-s\tchange sort "
1007 "order\n");
1008 (void) fprintf(stderr, "\t-A\tset $TERMINFO "
1009 "for first term-name\n");
1010 (void) fprintf(stderr, "\t-B\tset $TERMINFO "
1011 "for other term-names\n");
1012 exit(-1);
1013 }
1014
1015 argc -= optind;
1016 argv += optind;
1017 optind = 0;
1018
1019 /* Default to $TERM for -n, -I, -C and -L options. */
1020 /* This is done by faking argv[][], argc and optind. */
1021 if (neither && (argc == 0 || argc == 1)) {
1022 if (argc == 0)
1023 tempargv[0] = term;
1024 else
1025 tempargv[0] = argv[optind];
1026 tempargv[1] = term;
1027 argc = 2;
1028 argv = tempargv;
1029 optind = 0;
1030 } else if ((printing != pr_none) && (argc == 0)) {
1031 tempargv[0] = term;
1032 argc = 1;
1033 argv = tempargv;
1034 optind = 0;
1035 }
1036
1037 /* Check for enough names. */
1038 if ((use || diff || common) && (argc <= 1)) {
1039 (void) fprintf(stderr,
1040 "%s: must have at least two terminal names for a "
1041 "comparison to be done.\n", progname);
1042 goto usage;
1043 }
1044
1045 /* Set the default of diff -d or print -I */
1046 if (!use && (printing == pr_none) && !common && !neither) {
1047 if (argc == 0 || argc == 1) {
1048 if (argc == 0) {
1049 tempargv[0] = term;
1050 argc = 1;
1051 argv = tempargv;
1052 optind = 0;
1053 }
1054 pr_init(printing = pr_terminfo);
1055 } else
1056 diff++;
1057 }
1058
1059 /* Set the default sorting order. */
1060 if (sortorder == none)
1061 switch ((int) printing) {
1062 case (int) pr_cap:
1063 sortorder = by_cap; break;
1064 case (int) pr_longnames:
1065 sortorder = by_longnames; break;
1066 case (int) pr_terminfo:
1067 case (int) pr_none:
1068 sortorder = by_terminfo; break;
1069 }
1070
1071 firstterm = argv[optind++];
1072 firstoptind = optind;
1073
1074 allocvariables(argc, firstoptind);
1075 sortnames();
1076
1077 devnull = open("/dev/null", O_RDWR);
1078 local_setenv(term1info);
1079 initfirstterm(firstterm);
1080 local_setenv(term2info);
1081 for (i = 0; optind < argc; optind++, i++)
1082 check_nth_terminal(argv[optind], i);
1083
1084 if (use)
1085 dorelative(firstoptind, argc, argv);
1086
1087 return (0);
1088 }
1089