9804 hal-set-property should support --direct option
[unleashed.git] / usr / src / cmd / infocmp / infocmp.c
blobcdbcffa447c46927d209dd548ea74c8d3ce71c50
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
22 /* Copyright (c) 1988 AT&T */
23 /* All Rights Reserved */
27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13 */
34 NAME
35 infocmp - compare terminfo descriptions, or dump a terminfo
36 description
38 AUTHOR
39 Tony Hansen, February 23, 1984.
42 #include "curses.h"
43 #include "term.h"
44 #include "print.h"
45 #include <fcntl.h>
46 #include <stdlib.h>
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();
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();
73 /* data structures for this program */
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 */
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;
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;
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 */
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 */
137 #define EQUAL(s1, s2) (((s1 == NULL) && (s2 == NULL)) || \
138 ((s1 != NULL) && (s2 != NULL) && \
139 (strcmp(s1, s2) == 0)))
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);
147 void
148 badmalloc()
150 (void) fprintf(stderr, "%s: malloc is out of space!\n", progname);
151 exit(-1);
155 Allocate and initialize the global data structures and variables.
157 void
158 allocvariables(int argc, int firstoptind)
160 register int i, nullseen;
162 /* find out how many names we are dealing with */
163 for (numbools = 0; boolnames[numbools]; numbools++)
165 for (numnums = 0; numnames[numnums]; numnums++)
167 for (numstrs = 0; strnames[numstrs]; numstrs++)
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);
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));
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));
192 if ((ibool == NULL) || (num == NULL) || (str == NULL) ||
193 (use && (used == NULL)))
194 badmalloc();
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;
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;
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;
238 Routines to be passed to qsort(3) for comparison of the structures.
241 boolcompare(const void *x, const void *y)
243 struct boolstruct *a;
244 struct boolstruct *b;
246 a = (struct boolstruct *)x;
247 b = (struct boolstruct *)y;
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);
262 numcompare(const void *x, const void *y)
264 struct numstruct *a;
265 struct numstruct *b;
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);
282 strcompare(const void *x, const void *y)
284 struct strstruct *a;
285 struct strstruct *b;
287 a = (struct strstruct *)x;
288 b = (struct strstruct *)y;
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);
303 Sort the entries by their terminfo name.
305 static void
306 sortnames()
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);
316 return;
320 Print out a string, or "NULL" if it's not defined.
322 void
323 PR(FILE *stream, char *string)
325 if (string == NULL)
326 (void) fprintf(stream, "NULL");
327 else
328 tpr(stream, string);
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.
335 int kncounter;
336 char kobuffer[512];
338 char
339 *addko(char *output, char *input, char *koptr)
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++;
355 return (koptr);
358 void
359 setupknko()
361 char *koptr;
363 kncounter = 0;
364 koptr = kobuffer;
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 */
388 /* get rid of comma */
389 if (koptr != kobuffer)
390 *(--koptr) = '\0';
393 void
394 pr_kn()
396 if (kncounter > 0)
397 pr_number((char *)0, "kn", (char *)0, kncounter);
400 void
401 pr_ko()
403 if (kncounter > 0)
404 pr_string((char *)0, "ko", (char *)0, kobuffer);
407 void
408 pr_bcaps()
410 char *retptr;
411 char padbuffer[512];
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);
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);
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);
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);
436 /* Ignore "xr": Return acts like ce \r \n (Delta Data) */
439 void
440 pr_ncaps()
442 char padbuffer[512];
443 int padding;
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);
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);
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);
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);
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);
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);
486 /* Handle "kn": Number of "other" keys */
487 setupknko();
488 pr_kn();
491 void
492 pr_scaps()
494 char *retptr;
495 char padbuffer[512];
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);
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);
511 /* Handle "ko" here: Termcap entries for other non-function keys */
512 pr_ko();
514 /* Ignore "ma": Arrow key map, used by vi version 2 only */
518 Set up the first terminal and save the values from it.
520 void
521 initfirstterm(char *term)
523 register int i;
525 if (verbose)
526 (void) fprintf(trace, "setting up terminal type '%s'.\n",
527 term);
529 (void) setupterm(term, devnull, (int *) 0);
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;
545 } else
546 (void) strcpy(_savettytype, ttytype);
549 if (printing != pr_none) {
550 pr_heading(term, ttytype);
551 pr_bheading();
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);
565 if (printing != pr_none) {
566 if (printing == pr_cap)
567 pr_bcaps();
568 pr_bfooting();
569 pr_nheading();
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);
582 if (printing != pr_none) {
583 if (printing == pr_cap)
584 pr_ncaps();
585 pr_nfooting();
586 pr_sheading();
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");
601 if (printing == pr_cap)
602 pr_scaps();
604 if (printing != pr_none)
605 pr_sfooting();
609 Set up the n'th terminal.
611 static void
612 check_nth_terminal(char *nterm, int n)
614 register char boolval;
615 register short numval;
616 register char *strval;
617 register int i;
619 if (use)
620 used[n] = FALSE;
622 if (verbose)
623 (void) fprintf(trace, "adding in terminal type '%s'.\n",
624 nterm);
626 (void) setupterm(nterm, devnull, (int *) 0);
628 if (printing != pr_none) {
629 pr_heading(nterm, ttytype);
630 pr_bheading();
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");
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) {
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 ** }
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;
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);
698 if (printing != pr_none) {
699 if (printing == pr_cap)
700 pr_bcaps();
701 pr_bfooting();
702 pr_nheading();
705 if (diff || common || neither)
706 (void) printf(" comparing numbers.\n");
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);
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;
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);
754 if (printing != pr_none) {
755 if (printing == pr_cap)
756 pr_ncaps();
757 pr_nfooting();
758 pr_sheading();
761 if (diff || common || neither)
762 (void) printf(" comparing strings.\n");
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");
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;
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");
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");
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);
821 if (printing == pr_cap)
822 pr_scaps();
824 if (printing != pr_none)
825 pr_sfooting();
827 return;
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.
837 void
838 dorelative(int firstoptind, int argc, char **argv)
840 register int i;
842 /* turn off printing of termcap and long names */
843 pr_init(pr_terminfo);
845 /* print out the entry name */
846 pr_heading((char *)0, savettytype);
848 pr_bheading();
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);
859 pr_bfooting();
860 pr_nheading();
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);
871 pr_nfooting();
872 pr_sheading();
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);
883 pr_sfooting();
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]);
895 void
896 local_setenv(char *termNinfo)
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;
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));
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;
924 main(int argc, char **argv)
926 int i, c, firstoptind;
927 char *tempargv[2];
928 char *term = getenv("TERM");
930 term1info = term2info = getenv("TERMINFO");
931 progname = argv[0];
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);
1015 argc -= optind;
1016 argv += optind;
1017 optind = 0;
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;
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;
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;
1054 pr_init(printing = pr_terminfo);
1055 } else
1056 diff++;
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;
1071 firstterm = argv[optind++];
1072 firstoptind = optind;
1074 allocvariables(argc, firstoptind);
1075 sortnames();
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);
1084 if (use)
1085 dorelative(firstoptind, argc, argv);
1087 return (0);