infocmp.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13 */
/*
NAME
infocmp - compare terminfo descriptions, or dump a terminfo
description
AUTHOR
Tony Hansen, February 23, 1984.
*/
#include "curses.h"
#include "term.h"
#include "print.h"
#include <fcntl.h>
#include <stdlib.h>
/* externs from libcurses */
extern char *boolnames[];
extern char *boolcodes[];
extern char *boolfnames[];
extern char *numnames[];
extern char *numcodes[];
extern char *numfnames[];
extern char *strnames[];
extern char *strcodes[];
extern char *strfnames[];
extern char ttytype[];
extern int tgetflag();
extern int tgetnum();
extern char *tgetstr();
/* externs from libc */
extern void exit();
extern void qsort();
extern char *getenv();
extern int getopt();
extern int optind;
extern char *optarg;
extern char *strncpy(), *strcpy();
extern int strcmp(), strlen();
/* data structures for this program */
struct boolstruct {
char *infoname; /* the terminfo capability name */
char *capname; /* the termcap capability name */
char *fullname; /* the long C variable name */
char *secondname; /* the use= terminal w/ this value */
char val; /* the value */
char secondval; /* the value in the use= terminal */
char changed; /* a use= terminal changed the value */
char seenagain; /* a use= terminal had this entry */
};
struct numstruct {
char *infoname; /* ditto from above */
char *capname;
char *fullname;
char *secondname;
short val;
short secondval;
char changed;
char seenagain;
};
struct strstruct {
char *infoname; /* ditto from above */
char *capname;
char *fullname;
char *secondname;
char *val;
char *secondval;
char changed;
char seenagain;
};
/* globals for this file */
char *progname; /* argv[0], the name of the program */
static struct boolstruct *ibool; /* array of char information */
static struct numstruct *num; /* array of number information */
static struct strstruct *str; /* array of string information */
static char *used; /* usage statistics */
static int numbools; /* how many booleans there are */
static int numnums; /* how many numbers there are */
static int numstrs; /* how many strings there are */
#define TTYLEN 255
static char *firstterm; /* the name of the first terminal */
static char *savettytype; /* the synonyms of the first terminal */
static char _savettytype[TTYLEN+1]; /* the place to save those names */
static int devnull; /* open("/dev/null") for setupterm */
#define trace stderr /* send trace messages to stderr */
/* options */
static int verbose = 0; /* debugging printing level */
static int diff = 0; /* produce diff listing, the default */
static int common = 0; /* produce common listing */
static int neither = 0; /* list caps in neither entry */
static int use = 0; /* produce use= comparison listing */
static enum printtypes printing /* doing any of above printing at all */
= pr_none;
enum { none, by_database, by_terminfo, by_longnames, by_cap }
sortorder = none; /* sort the fields for printing */
static char *term1info, *term2info; /* $TERMINFO settings */
static int Aflag = 0, Bflag = 0; /* $TERMINFO was set with -A/-B */
#define EQUAL(s1, s2) (((s1 == NULL) && (s2 == NULL)) || \
((s1 != NULL) && (s2 != NULL) && \
(strcmp(s1, s2) == 0)))
static void sortnames();
int numcompare(const void *, const void *);
int boolcompare(const void *, const void *);
int strcompare(const void *, const void *);
static void check_nth_terminal(char *, int);
void
badmalloc()
{
(void) fprintf(stderr, "%s: malloc is out of space!\n", progname);
exit(-1);
}
/*
Allocate and initialize the global data structures and variables.
*/
void
allocvariables(int argc, int firstoptind)
{
register int i, nullseen;
/* find out how many names we are dealing with */
for (numbools = 0; boolnames[numbools]; numbools++)
;
for (numnums = 0; numnames[numnums]; numnums++)
;
for (numstrs = 0; strnames[numstrs]; numstrs++)
;
if (verbose) {
(void) fprintf(trace, "There are %d boolean capabilities.\n",
numbools);
(void) fprintf(trace, "There are %d numeric capabilities.\n",
numnums);
(void) fprintf(trace, "There are %d string capabilities.\n",
numstrs);
}
/* Allocate storage for the names and their values */
ibool = (struct boolstruct *) malloc((unsigned) numbools *
sizeof (struct boolstruct));
num = (struct numstruct *) malloc((unsigned) numnums *
sizeof (struct numstruct));
str = (struct strstruct *) malloc((unsigned) numstrs *
sizeof (struct strstruct));
/* Allocate array to keep track of which names have been used. */
if (use)
used = (char *) malloc((unsigned) (argc - firstoptind) *
sizeof (char));
if ((ibool == NULL) || (num == NULL) || (str == NULL) ||
(use && (used == NULL)))
badmalloc();
/* Fill in the names and initialize the structures. */
nullseen = FALSE;
for (i = 0; i < numbools; i++) {
ibool[i].infoname = boolnames[i];
ibool[i].capname = boolcodes[i];
/* This is necessary until fnames.c is */
/* incorporated into standard curses. */
if (nullseen || (boolfnames[i] == NULL)) {
ibool[i].fullname = "unknown_boolean";
nullseen = TRUE;
} else
ibool[i].fullname = boolfnames[i];
ibool[i].changed = FALSE;
ibool[i].seenagain = FALSE;
}
nullseen = 0;
for (i = 0; i < numnums; i++) {
num[i].infoname = numnames[i];
num[i].capname = numcodes[i];
if (nullseen || (numfnames[i] == NULL)) {
ibool[i].fullname = "unknown_number";
nullseen = TRUE;
} else
num[i].fullname = numfnames[i];
num[i].changed = FALSE;
num[i].seenagain = FALSE;
}
nullseen = 0;
for (i = 0; i < numstrs; i++) {
str[i].infoname = strnames[i];
str[i].capname = strcodes[i];
if (nullseen || (strfnames[i] == NULL)) {
str[i].fullname = "unknown_string";
nullseen = TRUE;
} else
str[i].fullname = strfnames[i];
str[i].changed = FALSE;
str[i].seenagain = FALSE;
}
}
/*
Routines to be passed to qsort(3) for comparison of the structures.
*/
int
boolcompare(const void *x, const void *y)
{
struct boolstruct *a;
struct boolstruct *b;
a = (struct boolstruct *)x;
b = (struct boolstruct *)y;
switch ((int) sortorder) {
case (int) by_terminfo:
return (strcmp(a->infoname, b->infoname));
case (int) by_cap:
return (strcmp(a->capname, b->capname));
case (int) by_longnames:
return (strcmp(a->fullname, b->fullname));
default:
return (0);
}
}
int
numcompare(const void *x, const void *y)
{
struct numstruct *a;
struct numstruct *b;
a = (struct numstruct *)x;
b = (struct numstruct *)y;
switch ((int) sortorder) {
case (int) by_terminfo:
return (strcmp(a->infoname, b->infoname));
case (int) by_cap:
return (strcmp(a->capname, b->capname));
case (int) by_longnames:
return (strcmp(a->fullname, b->fullname));
default:
return (0);
}
}
int
strcompare(const void *x, const void *y)
{
struct strstruct *a;
struct strstruct *b;
a = (struct strstruct *)x;
b = (struct strstruct *)y;
switch ((int) sortorder) {
case (int) by_terminfo:
return (strcmp(a->infoname, b->infoname));
case (int) by_cap:
return (strcmp(a->capname, b->capname));
case (int) by_longnames:
return (strcmp(a->fullname, b->fullname));
default:
return (0);
}
}
/*
Sort the entries by their terminfo name.
*/
static void
sortnames()
{
if (sortorder != by_database) {
qsort((char *) ibool, (unsigned) numbools,
sizeof (struct boolstruct), boolcompare);
qsort((char *) num, (unsigned) numnums,
sizeof (struct numstruct), numcompare);
qsort((char *) str, (unsigned) numstrs,
sizeof (struct strstruct), strcompare);
}
return;
}
/*
Print out a string, or "NULL" if it's not defined.
*/
void
PR(FILE *stream, char *string)
{
if (string == NULL)
(void) fprintf(stream, "NULL");
else
tpr(stream, string);
}
/*
Output the 'ko' termcap string. This is a list of all of the input
keys that input the same thing as the corresponding output strings.
*/
int kncounter;
char kobuffer[512];
char
*addko(char *output, char *input, char *koptr)
{
char *inptr, *outptr, padbuffer[512];
inptr = tgetstr(input, (char **)0);
if (inptr == NULL)
return (koptr);
outptr = tgetstr(output, (char **)0);
if (outptr == NULL)
return (koptr);
outptr = rmpadding(outptr, padbuffer, (int *) 0);
if (strcmp(inptr, outptr) == 0) {
*koptr++ = *output++;
*koptr++ = *output++;
*koptr++ = ',';
kncounter++;
}
return (koptr);
}
void
setupknko()
{
char *koptr;
kncounter = 0;
koptr = kobuffer;
koptr = addko("bs", "kb", koptr); /* key_backspace */
koptr = addko("bt", "kB", koptr); /* key_btab */
koptr = addko("cl", "kC", koptr); /* key_clear */
koptr = addko("le", "kl", koptr); /* key_left */
koptr = addko("do", "kd", koptr); /* key_down */
koptr = addko("nd", "kr", koptr); /* key_right */
koptr = addko("up", "ku", koptr); /* key_up */
koptr = addko("dc", "kD", koptr); /* key_dc */
koptr = addko("dl", "kL", koptr); /* key_dl */
koptr = addko("cd", "kS", koptr); /* key_eos */
koptr = addko("ce", "kE", koptr); /* key_eol */
koptr = addko("ho", "kh", koptr); /* key_home */
koptr = addko("st", "kT", koptr); /* key_stab */
koptr = addko("ic", "kI", koptr); /* key_ic */
koptr = addko("im", "kI", koptr); /* key_ic */
koptr = addko("al", "kA", koptr); /* key_il */
koptr = addko("sf", "kF", koptr); /* key_sf */
koptr = addko("ll", "kH", koptr); /* key_ll */
koptr = addko("sr", "kR", koptr); /* key_sr */
koptr = addko("ei", "kM", koptr); /* key_eic */
koptr = addko("ct", "ka", koptr); /* key_catab */
/* get rid of comma */
if (koptr != kobuffer)
*(--koptr) = '\0';
}
void
pr_kn()
{
if (kncounter > 0)
pr_number((char *)0, "kn", (char *)0, kncounter);
}
void
pr_ko()
{
if (kncounter > 0)
pr_string((char *)0, "ko", (char *)0, kobuffer);
}
void
pr_bcaps()
{
char *retptr;
char padbuffer[512];
if (verbose)
(void) fprintf(trace, "looking at 'bs'\n");
retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0));
if (strcmp("\\b", retptr) == 0)
pr_boolean((char *)0, "bs", (char *)0, 1);
if (verbose)
(void) fprintf(trace, "looking at 'pt'\n");
retptr = cconvert(rmpadding(tab, padbuffer, (int *) 0));
if (strcmp("\\t", retptr) == 0)
pr_boolean((char *)0, "pt", (char *)0, 1);
if (verbose)
(void) fprintf(trace, "looking at 'nc'\n");
retptr = cconvert(rmpadding(carriage_return, padbuffer, (int *) 0));
if (strcmp("\\r", retptr) != 0)
pr_boolean((char *)0, "nc", (char *)0, 1);
if (verbose)
(void) fprintf(trace, "looking at 'ns'\n");
if (scroll_forward == NULL)
pr_boolean((char *)0, "ns", (char *)0, 1);
/* Ignore "xr": Return acts like ce \r \n (Delta Data) */
}
void
pr_ncaps()
{
char padbuffer[512];
int padding;
if (verbose)
(void) fprintf(trace, "looking at 'ug'\n");
/* Duplicate sg for ug: Number of blank chars left by us or ue */
if (magic_cookie_glitch > -1)
pr_number((char *)0, "ug", (char *)0, magic_cookie_glitch);
if (verbose)
(void) fprintf(trace, "looking at 'dB'\n");
/* Number of millisec of bs delay needed */
(void) rmpadding(cursor_left, padbuffer, &padding);
if (padding > 0)
pr_number((char *)0, "dB", (char *)0, padding);
if (verbose)
(void) fprintf(trace, "looking at 'dC'\n");
/* Number of millisec of cr delay needed */
(void) rmpadding(carriage_return, padbuffer, &padding);
if (padding > 0)
pr_number((char *)0, "dC", (char *)0, padding);
if (verbose)
(void) fprintf(trace, "looking at 'dF'\n");
/* Number of millisec of ff delay needed */
(void) rmpadding(form_feed, padbuffer, &padding);
if (padding > 0)
pr_number((char *)0, "dF", (char *)0, padding);
if (verbose)
(void) fprintf(trace, "looking at 'dN'\n");
/* Number of millisec of nl delay needed */
(void) rmpadding(cursor_down, padbuffer, &padding);
if (padding > 0)
pr_number((char *)0, "dN", (char *)0, padding);
if (verbose)
(void) fprintf(trace, "looking at 'dT'\n");
/* Number of millisec of tab delay needed */
(void) rmpadding(tab, padbuffer, &padding);
if (padding > 0)
pr_number((char *)0, "dT", (char *)0, padding);
/* Handle "kn": Number of "other" keys */
setupknko();
pr_kn();
}
void
pr_scaps()
{
char *retptr;
char padbuffer[512];
/* Backspace if not "^H" */
if (verbose)
(void) fprintf(trace, "looking at 'bc'\n");
retptr = cconvert(rmpadding(cursor_left, padbuffer, (int *) 0));
if (strcmp("\\b", retptr) != 0)
pr_string((char *)0, "bc", (char *)0, cursor_left);
/* Newline character (default "\n") */
if (verbose)
(void) fprintf(trace, "looking at 'nl'\n");
retptr = cconvert(rmpadding(cursor_down, padbuffer, (int *) 0));
if (strcmp("\\n", retptr) != 0)
pr_string((char *)0, "nl", (char *)0, cursor_down);
/* Handle "ko" here: Termcap entries for other non-function keys */
pr_ko();
/* Ignore "ma": Arrow key map, used by vi version 2 only */
}
/*
Set up the first terminal and save the values from it.
*/
void
initfirstterm(char *term)
{
register int i;
if (verbose)
(void) fprintf(trace, "setting up terminal type '%s'.\n",
term);
(void) setupterm(term, devnull, (int *) 0);
/* Save the name for later use. */
if (use) {
register unsigned int length;
savettytype = _savettytype;
if ((length = strlen(ttytype)) >= TTYLEN) {
savettytype = malloc(length);
if (savettytype == NULL) {
(void) fprintf(stderr, "%s: malloc is out "
"of space\n", progname);
(void) strncpy(_savettytype, ttytype,
TTYLEN-1);
_savettytype[TTYLEN] = '\0';
savettytype = _savettytype;
}
} else
(void) strcpy(_savettytype, ttytype);
}
if (printing != pr_none) {
pr_heading(term, ttytype);
pr_bheading();
}
/* Save the values for the first terminal. */
for (i = 0; i < numbools; i++) {
if ((ibool[i].val = tgetflag(ibool[i].capname)) &&
printing != pr_none)
pr_boolean(ibool[i].infoname, ibool[i].capname,
ibool[i].fullname, 1);
if (verbose)
(void) fprintf(trace, "%s=%d.\n", ibool[i].infoname,
ibool[i].val);
}
if (printing != pr_none) {
if (printing == pr_cap)
pr_bcaps();
pr_bfooting();
pr_nheading();
}
for (i = 0; i < numnums; i++) {
if (((num[i].val = tgetnum(num[i].capname)) > -1) &&
printing != pr_none)
pr_number(num[i].infoname, num[i].capname,
num[i].fullname, num[i].val);
if (verbose)
(void) fprintf(trace, "%s=%d.\n", num[i].infoname,
num[i].val);
}
if (printing != pr_none) {
if (printing == pr_cap)
pr_ncaps();
pr_nfooting();
pr_sheading();
}
for (i = 0; i < numstrs; i++) {
str[i].val = tgetstr(str[i].capname, (char **)0);
if ((str[i].val != NULL) && printing != pr_none)
pr_string(str[i].infoname, str[i].capname,
str[i].fullname, str[i].val);
if (verbose) {
(void) fprintf(trace, "%s='", str[i].infoname);
PR(trace, str[i].val);
(void) fprintf(trace, "'.\n");
}
}
if (printing == pr_cap)
pr_scaps();
if (printing != pr_none)
pr_sfooting();
}
/*
Set up the n'th terminal.
*/
static void
check_nth_terminal(char *nterm, int n)
{
register char boolval;
register short numval;
register char *strval;
register int i;
if (use)
used[n] = FALSE;
if (verbose)
(void) fprintf(trace, "adding in terminal type '%s'.\n",
nterm);
(void) setupterm(nterm, devnull, (int *) 0);
if (printing != pr_none) {
pr_heading(nterm, ttytype);
pr_bheading();
}
if (diff || common || neither) {
if (Aflag && Bflag)
(void) printf("comparing %s (TERMINFO=%s) to %s "
"(TERMINFO=%s).\n",
firstterm, term1info, nterm, term2info);
else if (Aflag)
(void) printf("comparing %s (TERMINFO=%s) to %s.\n",
firstterm, term1info, nterm);
else if (Bflag)
(void) printf("comparing %s to %s (TERMINFO=%s).\n",
firstterm, nterm, term2info);
else
(void) printf("comparing %s to %s.\n",
firstterm, nterm);
(void) printf(" comparing booleans.\n");
}
/* save away the values for the nth terminal */
for (i = 0; i < numbools; i++) {
boolval = tgetflag(ibool[i].capname);
if (use) {
if (ibool[i].seenagain) {
/*
** We do not have to worry about this impossible case
** since booleans can have only two values: true and
** false.
** if (boolval && (boolval != ibool[i].secondval))
** {
** (void) fprintf(trace, "use= order dependency"
** "found:\n");
** (void) fprintf(trace, " %s: %s has %d, %s has"
** " %d.\n",
** ibool[i].capname, ibool[i].secondname,
** ibool[i].secondval, nterm, boolval);
** }
*/
} else {
if (boolval == TRUE) {
ibool[i].seenagain = TRUE;
ibool[i].secondval = boolval;
ibool[i].secondname = nterm;
if (ibool[i].val != boolval)
ibool[i].changed = TRUE;
else
used[n] = TRUE;
}
}
}
if (boolval) {
if (printing != pr_none)
pr_boolean(ibool[i].infoname, ibool[i].capname,
ibool[i].fullname, 1);
if (common && (ibool[i].val == boolval))
(void) printf("\t%s= T.\n", ibool[i].infoname);
} else if (neither && !ibool[i].val)
(void) printf("\t!%s.\n", ibool[i].infoname);
if (diff && (ibool[i].val != boolval))
(void) printf("\t%s: %c:%c.\n", ibool[i].infoname,
ibool[i].val?'T':'F', boolval?'T':'F');
if (verbose)
(void) fprintf(trace, "%s: %d:%d, changed=%d, "
"seen=%d.\n", ibool[i].infoname, ibool[i].val,
boolval, ibool[i].changed, ibool[i].seenagain);
}
if (printing != pr_none) {
if (printing == pr_cap)
pr_bcaps();
pr_bfooting();
pr_nheading();
}
if (diff || common || neither)
(void) printf(" comparing numbers.\n");
for (i = 0; i < numnums; i++) {
numval = tgetnum(num[i].capname);
if (use) {
if (num[i].seenagain) {
if ((numval > -1) &&
(numval != num[i].secondval)) {
(void) fprintf(stderr,
"%s: use = order dependency "
"found:\n", progname);
(void) fprintf(stderr, " %s: %s "
"has %d, %s has %d.\n",
num[i].capname, num[i].secondname,
num[i].secondval, nterm, numval);
}
} else {
if (numval > -1) {
num[i].seenagain = TRUE;
num[i].secondval = numval;
num[i].secondname = nterm;
if ((numval > -1) &&
(num[i].val != numval))
num[i].changed = TRUE;
else
used[n] = TRUE;
}
}
}
if (numval > -1) {
if (printing != pr_none)
pr_number(num[i].infoname, num[i].capname,
num[i].fullname, numval);
if (common && (num[i].val == numval))
(void) printf("\t%s= %d.\n", num[i].infoname,
numval);
} else if (neither && (num[i].val == -1))
(void) printf("\t!%s.\n", num[i].infoname);
if (diff && (num[i].val != numval))
(void) printf("\t%s: %d:%d.\n",
num[i].infoname, num[i].val, numval);
if (verbose)
(void) fprintf(trace, "%s: %d:%d, "
"changed = %d, seen = %d.\n",
num[i].infoname, num[i].val, numval,
num[i].changed, num[i].seenagain);
}
if (printing != pr_none) {
if (printing == pr_cap)
pr_ncaps();
pr_nfooting();
pr_sheading();
}
if (diff || common || neither)
(void) printf(" comparing strings.\n");
for (i = 0; i < numstrs; i++) {
strval = tgetstr(str[i].capname, (char **)0);
if (use) {
if (str[i].seenagain && (strval != NULL)) {
if (!EQUAL(strval, str[i].secondval)) {
(void) fprintf(stderr,
"use= order dependency"
" found:\n");
(void) fprintf(stderr,
" %s: %s has '",
str[i].capname, str[i].secondname);
PR(stderr, str[i].secondval);
(void) fprintf(stderr,
"', %s has '", nterm);
PR(stderr, strval);
(void) fprintf(stderr, "'.\n");
}
} else {
if (strval != NULL) {
str[i].seenagain = TRUE;
str[i].secondval = strval;
str[i].secondname = nterm;
if (!EQUAL(str[i].val, strval))
str[i].changed = TRUE;
else
used[n] = TRUE;
}
}
}
if (strval != NULL) {
if (printing != pr_none)
pr_string(str[i].infoname, str[i].capname,
str[i].fullname, strval);
if (common && EQUAL(str[i].val, strval)) {
(void) printf("\t%s= '", str[i].infoname);
PR(stdout, strval);
(void) printf("'.\n");
}
} else if (neither && (str[i].val == NULL))
(void) printf("\t!%s.\n", str[i].infoname);
if (diff && !EQUAL(str[i].val, strval)) {
(void) printf("\t%s: '", str[i].infoname);
PR(stdout, str[i].val);
(void) printf("','");
PR(stdout, strval);
(void) printf("'.\n");
}
if (verbose) {
(void) fprintf(trace, "%s: '", str[i].infoname);
PR(trace, str[i].val);
(void) fprintf(trace, "':'");
PR(trace, strval);
(void) fprintf(trace, "',changed=%d,seen=%d.\n",
str[i].changed, str[i].seenagain);
}
}
if (printing == pr_cap)
pr_scaps();
if (printing != pr_none)
pr_sfooting();
return;
}
/*
A capability gets an at-sign if it no longer exists, but
one of the relative entries contains a value for it.
It gets printed if the original value is not seen in ANY
of the relative entries, or if the FIRST relative entry that has
the capability gives a DIFFERENT value for the capability.
*/
void
dorelative(int firstoptind, int argc, char **argv)
{
register int i;
/* turn off printing of termcap and long names */
pr_init(pr_terminfo);
/* print out the entry name */
pr_heading((char *)0, savettytype);
pr_bheading();
/* Print out all bools that are different. */
for (i = 0; i < numbools; i++)
if (!ibool[i].val && ibool[i].changed)
pr_boolean(ibool[i].infoname, (char *)0,
(char *)0, -1);
else if (ibool[i].val && (ibool[i].changed ||
!ibool[i].seenagain))
pr_boolean(ibool[i].infoname, (char *)0, (char *)0, 1);
pr_bfooting();
pr_nheading();
/* Print out all nums that are different. */
for (i = 0; i < numnums; i++)
if (num[i].val < 0 && num[i].changed)
pr_number(num[i].infoname, (char *)0, (char *)0, -1);
else if (num[i].val >= 0 && (num[i].changed ||
!num[i].seenagain))
pr_number(num[i].infoname, (char *)0,
(char *)0, num[i].val);
pr_nfooting();
pr_sheading();
/* Print out all strs that are different. */
for (i = 0; i < numstrs; i++)
if (str[i].val == NULL && str[i].changed)
pr_string(str[i].infoname, (char *)0, (char *)0,
(char *)0);
else if ((str[i].val != NULL) &&
(str[i].changed || !str[i].seenagain))
pr_string(str[i].infoname, (char *)0, (char *)0, str[i].val);
pr_sfooting();
/* Finish it up. */
for (i = firstoptind; i < argc; i++)
if (used[i - firstoptind])
(void) printf("\tuse=%s,\n", argv[i]);
else
(void) fprintf(stderr,
"%s: 'use=%s' did not add anything to the "
"description.\n", progname, argv[i]);
}
void
local_setenv(char *termNinfo)
{
extern char **environ;
static char *newenviron[2] = { 0, 0 };
static unsigned int termsize = BUFSIZ;
static char _terminfo[BUFSIZ];
static char *terminfo = &_terminfo[0];
register int termlen;
if (termNinfo && *termNinfo) {
if (verbose)
(void) fprintf(trace, "setting TERMINFO=%s.\n",
termNinfo);
termlen = strlen(termNinfo);
if (termlen + 10 > termsize) {
termsize = termlen + 20;
terminfo = (char *) malloc(termsize * sizeof (char));
}
if (terminfo == (char *) NULL)
badmalloc();
(void) sprintf(terminfo, "TERMINFO=%s", termNinfo);
newenviron[0] = terminfo;
} else
newenviron[0] = (char *) 0;
environ = newenviron;
}
int
main(int argc, char **argv)
{
int i, c, firstoptind;
char *tempargv[2];
char *term = getenv("TERM");
term1info = term2info = getenv("TERMINFO");
progname = argv[0];
/* parse options */
while ((c = getopt(argc, argv, "ducnILCvV1rw:s:A:B:")) != EOF)
switch (c) {
case 'v': verbose++;
break;
case '1': pr_onecolumn(1);
break;
case 'w': pr_width(atoi(optarg));
break;
case 'd': diff++;
break;
case 'c': common++;
break;
case 'n': neither++;
break;
case 'u': use++;
break;
case 'L': pr_init(printing = pr_longnames);
break;
case 'I': pr_init(printing = pr_terminfo);
break;
case 'C': pr_init(printing = pr_cap);
break;
case 'A': term1info = optarg; Aflag++;
break;
case 'B': term2info = optarg; Bflag++;
break;
case 'r': pr_caprestrict(0);
break;
case 's':
if (strcmp(optarg, "d") == 0)
sortorder = by_database;
else if (strcmp(optarg, "i") == 0)
sortorder = by_terminfo;
else if (strcmp(optarg, "l") == 0)
sortorder = by_longnames;
else if (strcmp(optarg, "c") == 0)
sortorder = by_cap;
else
goto usage;
break;
case 'V':
(void) printf("%s: version %s\n", progname,
"@(#)curses:screen/infocmp.c 1.13");
exit(0);
case '?':
usage:
(void) fprintf(stderr,
"usage: %s [-ducn] [-ILC] [-1Vv] "
"[-s d|i|l|c] [-A directory] "
"[-B directory] term-names ...\n",
progname);
(void) fprintf(stderr, "\t-d\tprint "
"differences (the default for >1 "
"term-name)\n");
(void) fprintf(stderr, "\t-u\tproduce "
"relative description\n");
(void) fprintf(stderr, "\t-c\tprint common "
"entries\n");
(void) fprintf(stderr, "\t-n\tprint entries "
"in neither\n");
(void) fprintf(stderr, "\t-I\tprint terminfo "
"entries (the default for 1 term-name)\n");
(void) fprintf(stderr, "\t-C\tprint termcap "
"entries\n");
(void) fprintf(stderr, "\t-L\tprint long C "
"variable names\n");
(void) fprintf(stderr, "\t-1\tsingle column "
"output\n");
(void) fprintf(stderr, "\t-V\tprint program "
"version\n");
(void) fprintf(stderr, "\t-v\tverbose "
"debugging output\n");
(void) fprintf(stderr, "\t-s\tchange sort "
"order\n");
(void) fprintf(stderr, "\t-A\tset $TERMINFO "
"for first term-name\n");
(void) fprintf(stderr, "\t-B\tset $TERMINFO "
"for other term-names\n");
exit(-1);
}
argc -= optind;
argv += optind;
optind = 0;
/* Default to $TERM for -n, -I, -C and -L options. */
/* This is done by faking argv[][], argc and optind. */
if (neither && (argc == 0 || argc == 1)) {
if (argc == 0)
tempargv[0] = term;
else
tempargv[0] = argv[optind];
tempargv[1] = term;
argc = 2;
argv = tempargv;
optind = 0;
} else if ((printing != pr_none) && (argc == 0)) {
tempargv[0] = term;
argc = 1;
argv = tempargv;
optind = 0;
}
/* Check for enough names. */
if ((use || diff || common) && (argc <= 1)) {
(void) fprintf(stderr,
"%s: must have at least two terminal names for a "
"comparison to be done.\n", progname);
goto usage;
}
/* Set the default of diff -d or print -I */
if (!use && (printing == pr_none) && !common && !neither) {
if (argc == 0 || argc == 1) {
if (argc == 0) {
tempargv[0] = term;
argc = 1;
argv = tempargv;
optind = 0;
}
pr_init(printing = pr_terminfo);
} else
diff++;
}
/* Set the default sorting order. */
if (sortorder == none)
switch ((int) printing) {
case (int) pr_cap:
sortorder = by_cap; break;
case (int) pr_longnames:
sortorder = by_longnames; break;
case (int) pr_terminfo:
case (int) pr_none:
sortorder = by_terminfo; break;
}
firstterm = argv[optind++];
firstoptind = optind;
allocvariables(argc, firstoptind);
sortnames();
devnull = open("/dev/null", O_RDWR);
local_setenv(term1info);
initfirstterm(firstterm);
local_setenv(term2info);
for (i = 0; optind < argc; optind++, i++)
check_nth_terminal(argv[optind], i);
if (use)
dorelative(firstoptind, argc, argv);
return (0);
}