Import infocmp from NetBSD
Convert the content of the terminfo database into human-readable form, the same as used by the tic(1) command already present.
This commit is contained in:
parent
1999c518b6
commit
5139afee6b
6 changed files with 940 additions and 1 deletions
|
@ -253,6 +253,7 @@
|
|||
./usr/bin/ifconfig minix-sys
|
||||
./usr/bin/ifdef minix-sys
|
||||
./usr/bin/indent minix-sys
|
||||
./usr/bin/infocmp minix-sys
|
||||
./usr/bin/in.fingerd minix-sys
|
||||
./usr/bin/in.rshd minix-sys
|
||||
./usr/bin/install minix-sys
|
||||
|
@ -1222,6 +1223,7 @@
|
|||
./usr/man/man1/if.1 minix-sys
|
||||
./usr/man/man1/ifdef.1 minix-sys
|
||||
./usr/man/man1/indent.1 minix-sys
|
||||
./usr/man/man1/infocmp.1 minix-sys
|
||||
./usr/man/man1/install.1 minix-sys
|
||||
./usr/man/man1/isodir.1 minix-sys
|
||||
./usr/man/man1/isoinfo.1 minix-sys
|
||||
|
|
|
@ -121,6 +121,7 @@
|
|||
2012/10/17 12:00:00,usr.bin/genassym
|
||||
2012/10/17 12:00:00,usr.bin/gzip
|
||||
2012/10/17 12:00:00,usr.bin/indent
|
||||
2012/10/17 12:00:00,usr.bin/infocmp
|
||||
2012/10/17 12:00:00,usr.bin/join
|
||||
2011/01/17 18:11:10,usr.bin/ldd
|
||||
2012/02/10 16:16:12,usr.bin/login
|
||||
|
|
|
@ -12,7 +12,7 @@ SUBDIR= \
|
|||
\
|
||||
\
|
||||
genassym \
|
||||
indent join \
|
||||
indent infocmp join \
|
||||
ldd \
|
||||
login lorder m4 \
|
||||
make man \
|
||||
|
|
10
usr.bin/infocmp/Makefile
Normal file
10
usr.bin/infocmp/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
# $NetBSD: Makefile,v 1.1 2010/02/03 15:16:33 roy Exp $
|
||||
|
||||
PROG= infocmp
|
||||
WARNS= 4
|
||||
|
||||
CPPFLAGS+= -I${.CURDIR}/../../lib/libterminfo
|
||||
LDADD+= -lterminfo
|
||||
DPADD+= ${LIBTERMINFO}
|
||||
|
||||
.include <bsd.prog.mk>
|
131
usr.bin/infocmp/infocmp.1
Normal file
131
usr.bin/infocmp/infocmp.1
Normal file
|
@ -0,0 +1,131 @@
|
|||
.\" $NetBSD: infocmp.1,v 1.5 2011/01/14 14:21:36 wiz Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" This code is derived from software contributed to The NetBSD Foundation
|
||||
.\" by Roy Marples.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
.\" POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd February 5, 2010
|
||||
.Dt INFOCMP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm infocmp
|
||||
.Nd compare or print compiled terminfo descriptions
|
||||
.Sh SYNOPSIS
|
||||
.Nm infocmp
|
||||
.Op Fl 1acnqux
|
||||
.Op Fl A Ar database
|
||||
.Op Fl B Ar database
|
||||
.Op Fl w Ar cols
|
||||
.Op Ar term ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
reconstructs the first available
|
||||
.Xr terminfo 5
|
||||
definition found for
|
||||
.Ar term
|
||||
and prints the result in a
|
||||
.Xr terminfo 5
|
||||
format.
|
||||
Capability types are grouped together and new types start new lines,
|
||||
first flags, then numbers, then strings.
|
||||
Capabilities are sorted by their name.
|
||||
If a second
|
||||
.Ar term
|
||||
is given then the capabilities are compared against each other.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width Ev
|
||||
.It Fl 1
|
||||
Print one capability per line.
|
||||
.It Fl A Ar database
|
||||
Use this database to load the first terminal definition.
|
||||
.It Fl B Ar database
|
||||
Use this database to load subsequent terminal definitions.
|
||||
.It Fl a
|
||||
Include commented out capabilities.
|
||||
This only works if the database was compiled with the
|
||||
.Fl a
|
||||
flag passed to
|
||||
.Xr tic 1 .
|
||||
This also sets the
|
||||
.Fl x
|
||||
flag as
|
||||
.Nm
|
||||
retains commented out capabilities as non standard.
|
||||
.It Fl c
|
||||
Print capabilities common to each definition.
|
||||
.It Fl n
|
||||
Print capabilities that do not exist in either definition.
|
||||
.It Fl q
|
||||
Make the comparison listing shorter by omitting subheadings and using
|
||||
- for absent capabilities, @ for canceled capabilities rather than
|
||||
.Dv NULL .
|
||||
.It Fl u
|
||||
Build a new terminal description for the first terminal description,
|
||||
using subsequent terminal descriptions.
|
||||
This also sets the
|
||||
.Fl a
|
||||
flag.
|
||||
.It Fl w Ar cols
|
||||
Limit the width to
|
||||
.Ar cols .
|
||||
.It Fl x
|
||||
Include non-standard capabilities.
|
||||
More
|
||||
.Fl x
|
||||
only handles non-standard capabilities.
|
||||
This only works if the database was compiled with the
|
||||
.Fl x
|
||||
flag passed to
|
||||
.Xr tic 1 .
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width Ev
|
||||
.It Ev COLUMNS
|
||||
Override columns returned by the output terminal.
|
||||
.Fl w
|
||||
.Ar cols
|
||||
supersedes this.
|
||||
.It Ev TERM
|
||||
.Nm
|
||||
uses the contents of the
|
||||
.Ev TERM
|
||||
environment variable if no terminal name is given on the command line.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std infocmp
|
||||
.Sh SEE ALSO
|
||||
.Xr tic 1 ,
|
||||
.Xr terminfo 5
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility outputs information that conforms to the
|
||||
.St -xcurses4.2
|
||||
standard.
|
||||
.Sh AUTHORS
|
||||
.An Roy Marples Aq roy@NetBSD.org
|
795
usr.bin/infocmp/infocmp.c
Normal file
795
usr.bin/infocmp/infocmp.c
Normal file
|
@ -0,0 +1,795 @@
|
|||
/* $NetBSD: infocmp.c,v 1.7 2010/02/22 23:05:39 roy Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009, 2010 The NetBSD Foundation, Inc.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Roy Marples.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__RCSID("$NetBSD: infocmp.c,v 1.7 2010/02/22 23:05:39 roy Exp $");
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <term_private.h>
|
||||
#include <term.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Specifically needed on MINIX, as struct winsize in not defined elsewhere */
|
||||
#include <minix/termios.h>
|
||||
|
||||
#define SW 8
|
||||
|
||||
typedef struct tient {
|
||||
char type;
|
||||
const char *id;
|
||||
signed char flag;
|
||||
short num;
|
||||
const char *str;
|
||||
} TIENT;
|
||||
|
||||
static size_t cols;
|
||||
static int aflag, cflag, nflag, qflag, xflag;
|
||||
|
||||
static size_t
|
||||
outstr(FILE *f, const char *str)
|
||||
{
|
||||
unsigned char ch;
|
||||
size_t r, l;
|
||||
|
||||
r = 0;
|
||||
l = strlen(str);
|
||||
while ((ch = (unsigned char)(*str++)) != '\0') {
|
||||
switch (ch) {
|
||||
case 128:
|
||||
ch = '0';
|
||||
break;
|
||||
case '\033':
|
||||
ch = 'E';
|
||||
break;
|
||||
case '\014':
|
||||
ch = 'f';
|
||||
break;
|
||||
case '^': /* FALLTHROUGH */
|
||||
case ',': /* escape these */
|
||||
break;
|
||||
case ' ':
|
||||
ch = 's';
|
||||
break;
|
||||
default:
|
||||
if (ch == '\177') {
|
||||
if (f != NULL)
|
||||
fputc('^', f);
|
||||
ch = '?';
|
||||
r++;
|
||||
} else if (iscntrl(ch) &&
|
||||
ch < 128 &&
|
||||
ch != '\\' &&
|
||||
(l < 4 || isdigit((unsigned char)*str)))
|
||||
{
|
||||
if (f != NULL)
|
||||
fputc('^', f);
|
||||
ch += '@';
|
||||
r++;
|
||||
} else if (!isprint(ch)) {
|
||||
if (f != NULL)
|
||||
fprintf(f, "\\%03o", ch);
|
||||
r += 4;
|
||||
continue;
|
||||
}
|
||||
goto prnt;
|
||||
}
|
||||
|
||||
if (f != NULL)
|
||||
fputc('\\', f);
|
||||
r++;
|
||||
prnt:
|
||||
if (f != NULL)
|
||||
fputc(ch, f);
|
||||
r++;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
ent_compare(const void *a, const void *b)
|
||||
{
|
||||
const TIENT *ta, *tb;
|
||||
|
||||
ta = (const TIENT *)a;
|
||||
tb = (const TIENT *)b;
|
||||
return strcmp(ta->id, tb->id);
|
||||
}
|
||||
|
||||
static void
|
||||
setdb(char *db)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen(db);
|
||||
if (len > 3 &&
|
||||
db[len - 3] == '.' &&
|
||||
db[len - 2] == 'd' &&
|
||||
db[len - 1] == 'b')
|
||||
db[len - 3] = '\0';
|
||||
setenv("TERMINFO", db, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
print_ent(const TIENT *ents, size_t nents)
|
||||
{
|
||||
size_t col, i, l;
|
||||
char nbuf[64];
|
||||
|
||||
if (nents == 0)
|
||||
return;
|
||||
|
||||
col = SW;
|
||||
printf("\t");
|
||||
for (i = 0; i < nents; i++) {
|
||||
if (*ents[i].id == '.' && aflag == 0)
|
||||
continue;
|
||||
switch (ents[i].type) {
|
||||
case 'f':
|
||||
if (ents[i].flag == ABSENT_BOOLEAN)
|
||||
continue;
|
||||
l = strlen(ents[i].id) + 2;
|
||||
if (ents[i].flag == CANCELLED_BOOLEAN)
|
||||
l++;
|
||||
break;
|
||||
case 'n':
|
||||
if (ents[i].num == ABSENT_NUMERIC)
|
||||
continue;
|
||||
if (VALID_NUMERIC(ents[i].num))
|
||||
l = snprintf(nbuf, sizeof(nbuf), "%s#%d,",
|
||||
ents[i].id, ents[i].num);
|
||||
else
|
||||
l = snprintf(nbuf, sizeof(nbuf), "%s@,",
|
||||
ents[i].id);
|
||||
break;
|
||||
case 's':
|
||||
if (ents[i].str == ABSENT_STRING)
|
||||
continue;
|
||||
if (VALID_STRING(ents[i].str))
|
||||
l = strlen(ents[i].id) +
|
||||
outstr(NULL, ents[i].str) + 7;
|
||||
else
|
||||
l = strlen(ents[i].id) + 3;
|
||||
break;
|
||||
default:
|
||||
errx(1, "invalid type");
|
||||
}
|
||||
if (col != SW) {
|
||||
if (col + l > cols) {
|
||||
printf("\n\t");
|
||||
col = SW;
|
||||
} else
|
||||
col += printf(" ");
|
||||
}
|
||||
switch (ents[i].type) {
|
||||
case 'f':
|
||||
col += printf("%s", ents[i].id);
|
||||
if (ents[i].flag == ABSENT_BOOLEAN ||
|
||||
ents[i].flag == CANCELLED_BOOLEAN)
|
||||
col += printf("@");
|
||||
col += printf(",");
|
||||
break;
|
||||
case 'n':
|
||||
col += printf("%s", nbuf);
|
||||
break;
|
||||
case 's':
|
||||
col += printf("%s", ents[i].id);
|
||||
if (VALID_STRING(ents[i].str)) {
|
||||
col += printf("=");
|
||||
col += outstr(stdout, ents[i].str);
|
||||
} else
|
||||
col += printf("@");
|
||||
col += printf(",");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static size_t
|
||||
load_ents(TIENT *ents, TERMINAL *t, char type)
|
||||
{
|
||||
size_t i, n, max;
|
||||
TERMUSERDEF *ud;
|
||||
|
||||
switch (type) {
|
||||
case 'f':
|
||||
max = TIFLAGMAX;
|
||||
break;
|
||||
case 'n':
|
||||
max = TINUMMAX;
|
||||
break;
|
||||
default:
|
||||
max = TISTRMAX;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i <= max; i++) {
|
||||
switch (type) {
|
||||
case 'f':
|
||||
if (t->flags[i] == 1 ||
|
||||
(aflag && t->flags[i] == CANCELLED_BOOLEAN))
|
||||
{
|
||||
ents[n].id = _ti_flagid(i);
|
||||
ents[n].type = 'f';
|
||||
ents[n++].flag = t->flags[i];
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (VALID_NUMERIC(t->nums[i]) ||
|
||||
(aflag && t->nums[i] == CANCELLED_NUMERIC))
|
||||
{
|
||||
ents[n].id = _ti_numid(i);
|
||||
ents[n].type = 'n';
|
||||
ents[n++].num = t->nums[i];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (VALID_STRING(t->strs[i]) ||
|
||||
(aflag && t->strs[i] == CANCELLED_STRING))
|
||||
{
|
||||
ents[n].id = _ti_strid(i);
|
||||
ents[n].type = 's';
|
||||
ents[n++].str = t->strs[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (xflag != 0 && t->_nuserdefs != 0) {
|
||||
for (i = 0; i < t->_nuserdefs; i++) {
|
||||
ud = &t->_userdefs[i];
|
||||
if (ud->type == type) {
|
||||
switch (type) {
|
||||
case 'f':
|
||||
if (!aflag &&
|
||||
!VALID_BOOLEAN(ud->flag))
|
||||
continue;
|
||||
break;
|
||||
case 'n':
|
||||
if (!aflag &&
|
||||
!VALID_NUMERIC(ud->num))
|
||||
continue;
|
||||
break;
|
||||
case 's':
|
||||
if (!aflag &&
|
||||
!VALID_STRING(ud->str))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
ents[n].id = ud->id;
|
||||
ents[n].type = ud->type;
|
||||
ents[n].flag = ud->flag;
|
||||
ents[n].num = ud->num;
|
||||
ents[n++].str = ud->str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qsort(ents, n, sizeof(TIENT), ent_compare);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
cprint_ent(TIENT *ent)
|
||||
{
|
||||
|
||||
if (ent == NULL) {
|
||||
if (qflag == 0)
|
||||
printf("NULL");
|
||||
else
|
||||
printf("-");
|
||||
}
|
||||
|
||||
switch (ent->type) {
|
||||
case 'f':
|
||||
if (VALID_BOOLEAN(ent->flag))
|
||||
printf(ent->flag == 1 ? "T" : "F");
|
||||
else if (qflag == 0)
|
||||
printf("F");
|
||||
else if (ent->flag == CANCELLED_BOOLEAN)
|
||||
printf("@");
|
||||
else
|
||||
printf("-");
|
||||
break;
|
||||
case 'n':
|
||||
if (VALID_NUMERIC(ent->num))
|
||||
printf("%d", ent->num);
|
||||
else if (qflag == 0)
|
||||
printf("NULL");
|
||||
else if (ent->num == CANCELLED_NUMERIC)
|
||||
printf("@");
|
||||
else
|
||||
printf("-");
|
||||
break;
|
||||
case 's':
|
||||
if (VALID_STRING(ent->str)) {
|
||||
printf("'");
|
||||
outstr(stdout, ent->str);
|
||||
printf("'");
|
||||
} else if (qflag == 0)
|
||||
printf("NULL");
|
||||
else if (ent->str == CANCELLED_STRING)
|
||||
printf("@");
|
||||
else
|
||||
printf("-");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compare_ents(TIENT *ents1, size_t n1, TIENT *ents2, size_t n2)
|
||||
{
|
||||
size_t i1, i2;
|
||||
TIENT *e1, *e2, ee;
|
||||
int c;
|
||||
|
||||
i1 = i2 = 0;
|
||||
ee.type = 'f';
|
||||
ee.flag = ABSENT_BOOLEAN;
|
||||
ee.num = ABSENT_NUMERIC;
|
||||
ee.str = ABSENT_STRING;
|
||||
while (i1 != n1 || i2 != n2) {
|
||||
if (i1 == n1)
|
||||
c = 1;
|
||||
else if (i2 == n2)
|
||||
c = -1;
|
||||
else
|
||||
c = strcmp(ents1[i1].id, ents2[i2].id);
|
||||
if (c == 0) {
|
||||
e1 = &ents1[i1++];
|
||||
e2 = &ents2[i2++];
|
||||
} else if (c < 0) {
|
||||
e1 = &ents1[i1++];
|
||||
e2 = ⅇ
|
||||
ee.id = e1->id;
|
||||
ee.type = e1->type;
|
||||
} else {
|
||||
e1 = ⅇ
|
||||
e2 = &ents2[i2++];
|
||||
ee.id = e2->id;
|
||||
ee.type = e2->type;
|
||||
}
|
||||
switch (e1->type) {
|
||||
case 'f':
|
||||
if (cflag != 0) {
|
||||
if (e1->flag == e2->flag)
|
||||
printf("\t%s\n", ents1[i1].id);
|
||||
continue;
|
||||
}
|
||||
if (e1->flag == e2->flag)
|
||||
continue;
|
||||
break;
|
||||
case 'n':
|
||||
if (cflag != 0) {
|
||||
if (e1->num == e2->num)
|
||||
printf("\t%s#%d\n",
|
||||
ents1[i1].id, ents1[i1].num);
|
||||
continue;
|
||||
}
|
||||
if (e1->num == e2->num)
|
||||
continue;
|
||||
break;
|
||||
case 's':
|
||||
if (cflag != 0) {
|
||||
if (VALID_STRING(e1->str) &&
|
||||
VALID_STRING(e2->str) &&
|
||||
strcmp(e1->str, e2->str) == 0) {
|
||||
printf("\t%s=", ents1[i1].id);
|
||||
outstr(stdout, ents1[i1].str);
|
||||
printf("\n");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (VALID_STRING(e1->str) &&
|
||||
VALID_STRING(e2->str) &&
|
||||
strcmp(e1->str, e2->str) == 0)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
printf("\t%s: ", e1->id);
|
||||
cprint_ent(e1);
|
||||
if (e1->type == 'f')
|
||||
printf(":");
|
||||
else
|
||||
printf(", ");
|
||||
cprint_ent(e2);
|
||||
printf(".\n");
|
||||
}
|
||||
}
|
||||
|
||||
static TERMINAL *
|
||||
load_term(const char *name)
|
||||
{
|
||||
TERMINAL *t;
|
||||
|
||||
t = calloc(1, sizeof(*t));
|
||||
if (t == NULL)
|
||||
err(1, "calloc");
|
||||
if (name == NULL)
|
||||
name = getenv("TERM");
|
||||
if (name == NULL)
|
||||
name = "dumb";
|
||||
if (_ti_getterm(t, name, 1) == 1)
|
||||
return t;
|
||||
|
||||
if (_ti_database == NULL)
|
||||
errx(1, "no terminal definition found in internal database");
|
||||
else
|
||||
errx(1, "no terminal definition found in %s.db", _ti_database);
|
||||
}
|
||||
|
||||
static void
|
||||
show_missing(TERMINAL *t1, TERMINAL *t2, char type)
|
||||
{
|
||||
ssize_t i, max;
|
||||
const char *id;
|
||||
|
||||
switch (type) {
|
||||
case 'f':
|
||||
max = TIFLAGMAX;
|
||||
break;
|
||||
case 'n':
|
||||
max = TINUMMAX;
|
||||
break;
|
||||
default:
|
||||
max = TISTRMAX;
|
||||
}
|
||||
|
||||
for (i = 0; i <= max; i++) {
|
||||
switch (type) {
|
||||
case 'f':
|
||||
if (t1->flags[i] != ABSENT_BOOLEAN ||
|
||||
t2->flags[i] != ABSENT_BOOLEAN)
|
||||
continue;
|
||||
id = _ti_flagid(i);
|
||||
break;
|
||||
case 'n':
|
||||
if (t1->nums[i] != ABSENT_NUMERIC ||
|
||||
t2->nums[i] != ABSENT_NUMERIC)
|
||||
continue;
|
||||
id = _ti_numid(i);
|
||||
break;
|
||||
default:
|
||||
if (t1->strs[i] != ABSENT_STRING ||
|
||||
t2->strs[i] != ABSENT_STRING)
|
||||
continue;
|
||||
id = _ti_strid(i);
|
||||
break;
|
||||
}
|
||||
printf("\t!%s.\n", id);
|
||||
}
|
||||
}
|
||||
|
||||
static TERMUSERDEF *
|
||||
find_userdef(TERMINAL *term, const char *id)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < term->_nuserdefs; i++)
|
||||
if (strcmp(term->_userdefs[i].id, id) == 0)
|
||||
return &term->_userdefs[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
use_terms(TERMINAL *term, size_t nuse, char **uterms)
|
||||
{
|
||||
TERMINAL **terms;
|
||||
TERMUSERDEF *ud, *tud;
|
||||
size_t i, j, agree, absent, data;
|
||||
|
||||
terms = malloc(sizeof(**terms) * nuse);
|
||||
if (terms == NULL)
|
||||
err(1, "malloc");
|
||||
for (i = 0; i < nuse; i++) {
|
||||
if (strcmp(term->name, *uterms) == 0)
|
||||
errx(1, "cannot use same terminal");
|
||||
for (j = 0; j < i; j++)
|
||||
if (strcmp(terms[j]->name, *uterms) == 0)
|
||||
errx(1, "cannot use same terminal");
|
||||
terms[i] = load_term(*uterms++);
|
||||
}
|
||||
|
||||
for (i = 0; i < TIFLAGMAX + 1; i++) {
|
||||
agree = absent = data = 0;
|
||||
for (j = 0; j < nuse; j++) {
|
||||
if (terms[j]->flags[i] == ABSENT_BOOLEAN ||
|
||||
terms[j]->flags[i] == CANCELLED_BOOLEAN)
|
||||
absent++;
|
||||
else {
|
||||
data++;
|
||||
if (term->flags[i] == terms[j]->flags[i])
|
||||
agree++;
|
||||
}
|
||||
}
|
||||
if (data == 0)
|
||||
continue;
|
||||
if (agree > 0 && agree + absent == nuse)
|
||||
term->flags[i] = ABSENT_BOOLEAN;
|
||||
else if (term->flags[i] == ABSENT_BOOLEAN)
|
||||
term->flags[i] = CANCELLED_BOOLEAN;
|
||||
}
|
||||
|
||||
for (i = 0; i < TINUMMAX + 1; i++) {
|
||||
agree = absent = data = 0;
|
||||
for (j = 0; j < nuse; j++) {
|
||||
if (terms[j]->nums[i] == ABSENT_NUMERIC ||
|
||||
terms[j]->nums[i] == CANCELLED_NUMERIC)
|
||||
absent++;
|
||||
else {
|
||||
data++;
|
||||
if (term->nums[i] == terms[j]->nums[i])
|
||||
agree++;
|
||||
}
|
||||
}
|
||||
if (data == 0)
|
||||
continue;
|
||||
if (agree > 0 && agree + absent == nuse)
|
||||
term->nums[i] = ABSENT_NUMERIC;
|
||||
else if (term->nums[i] == ABSENT_NUMERIC)
|
||||
term->nums[i] = CANCELLED_NUMERIC;
|
||||
}
|
||||
|
||||
for (i = 0; i < TISTRMAX + 1; i++) {
|
||||
agree = absent = data = 0;
|
||||
for (j = 0; j < nuse; j++) {
|
||||
if (terms[j]->strs[i] == ABSENT_STRING ||
|
||||
terms[j]->strs[i] == CANCELLED_STRING)
|
||||
absent++;
|
||||
else {
|
||||
data++;
|
||||
if (VALID_STRING(term->strs[i]) &&
|
||||
strcmp(term->strs[i],
|
||||
terms[j]->strs[i]) == 0)
|
||||
agree++;
|
||||
}
|
||||
}
|
||||
if (data == 0)
|
||||
continue;
|
||||
if (agree > 0 && agree + absent == nuse)
|
||||
term->strs[i] = ABSENT_STRING;
|
||||
else if (term->strs[i] == ABSENT_STRING)
|
||||
term->strs[i] = CANCELLED_STRING;
|
||||
}
|
||||
|
||||
/* User defined caps are more tricky.
|
||||
First we set any to absent that agree. */
|
||||
for (i = 0; i < term->_nuserdefs; i++) {
|
||||
agree = absent = data = 0;
|
||||
ud = &term->_userdefs[i];
|
||||
for (j = 0; j < nuse; j++) {
|
||||
tud = find_userdef(terms[j], ud->id);
|
||||
if (tud == NULL)
|
||||
absent++;
|
||||
else {
|
||||
data++;
|
||||
switch (ud->type) {
|
||||
case 'f':
|
||||
if (tud->type == 'f' &&
|
||||
tud->flag == ud->flag)
|
||||
agree++;
|
||||
break;
|
||||
case 'n':
|
||||
if (tud->type == 'n' &&
|
||||
tud->num == ud->num)
|
||||
agree++;
|
||||
break;
|
||||
case 's':
|
||||
if (tud->type == 's' &&
|
||||
VALID_STRING(tud->str) &&
|
||||
VALID_STRING(ud->str) &&
|
||||
strcmp(ud->str, tud->str) == 0)
|
||||
agree++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data == 0)
|
||||
continue;
|
||||
if (agree > 0 && agree + absent == nuse) {
|
||||
ud->flag = ABSENT_BOOLEAN;
|
||||
ud->num = ABSENT_NUMERIC;
|
||||
ud->str = ABSENT_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now add any that we don't have as cancelled */
|
||||
for (i = 0; i < nuse; i++) {
|
||||
for (j = 0; j < terms[i]->_nuserdefs; j++) {
|
||||
ud = find_userdef(term, terms[i]->_userdefs[j].id);
|
||||
if (ud != NULL)
|
||||
continue; /* We have handled this */
|
||||
term->_userdefs = realloc(term->_userdefs,
|
||||
sizeof(*term->_userdefs) * (term->_nuserdefs + 1));
|
||||
if (term->_userdefs == NULL)
|
||||
err(1, "malloc");
|
||||
tud = &term->_userdefs[term->_nuserdefs++];
|
||||
tud->id = terms[i]->_userdefs[j].id;
|
||||
tud->type = terms[i]->_userdefs[j].flag;
|
||||
tud->flag = CANCELLED_BOOLEAN;
|
||||
tud->num = CANCELLED_NUMERIC;
|
||||
tud->str = CANCELLED_STRING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *term, *Barg;
|
||||
int ch, uflag;
|
||||
TERMINAL *t, *t2;
|
||||
size_t n, n2;
|
||||
struct winsize ws;
|
||||
TIENT ents[TISTRMAX + 1], ents2[TISTRMAX + 1];
|
||||
|
||||
cols = 80; /* default */
|
||||
term = getenv("COLUMNS");
|
||||
if (term != NULL)
|
||||
cols = strtoul(term, NULL, 10);
|
||||
else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0)
|
||||
cols = ws.ws_col;
|
||||
|
||||
uflag = xflag = 0;
|
||||
Barg = NULL;
|
||||
while ((ch = getopt(argc, argv, "1A:B:acnquw:x")) != -1)
|
||||
switch (ch) {
|
||||
case '1':
|
||||
cols = 1;
|
||||
break;
|
||||
case 'A':
|
||||
setdb(optarg);
|
||||
break;
|
||||
case 'B':
|
||||
Barg = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
aflag = 1;
|
||||
break;
|
||||
case 'c':
|
||||
cflag = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
break;
|
||||
case 'q':
|
||||
qflag = 1;
|
||||
break;
|
||||
case 'u':
|
||||
uflag = 1;
|
||||
aflag = 1;
|
||||
break;
|
||||
case 'w':
|
||||
cols = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'x':
|
||||
xflag = 1;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"usage: %s [-1acnqux] [-A database] [-B database] "
|
||||
"[-w cols] [term]\n",
|
||||
getprogname());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
cols--;
|
||||
|
||||
if (optind + 1 < argc)
|
||||
aflag = 1;
|
||||
|
||||
if (optind < argc)
|
||||
term = argv[optind++];
|
||||
else
|
||||
term = NULL;
|
||||
t = load_term(term);
|
||||
|
||||
if (uflag != 0)
|
||||
use_terms(t, argc - optind, argv + optind);
|
||||
|
||||
if ((optind + 1 != argc && nflag == 0) || uflag != 0) {
|
||||
if (uflag == 0) {
|
||||
printf("# Reconstructed from ");
|
||||
if (_ti_database == NULL)
|
||||
printf("internal database\n");
|
||||
else
|
||||
printf("%s%s\n", _ti_database,
|
||||
*_ti_database == '/' ? ".db" : "");
|
||||
}
|
||||
printf("%s", t->name);
|
||||
if (t->_alias != NULL && *t->_alias != '\0')
|
||||
printf("|%s", t->_alias);
|
||||
if (t->desc != NULL && *t->desc != '\0')
|
||||
printf("|%s", t->desc);
|
||||
printf(",\n");
|
||||
|
||||
n = load_ents(ents, t, 'f');
|
||||
print_ent(ents, n);
|
||||
n = load_ents(ents, t, 'n');
|
||||
print_ent(ents, n);
|
||||
n = load_ents(ents, t, 's');
|
||||
print_ent(ents, n);
|
||||
|
||||
if (uflag != 0) {
|
||||
printf("\t");
|
||||
n = SW;
|
||||
for (; optind < argc; optind++) {
|
||||
n2 = 5 + strlen(argv[optind]);
|
||||
if (n != SW) {
|
||||
if (n + n2 > cols) {
|
||||
printf("\n\t");
|
||||
n = SW;
|
||||
} else
|
||||
n += printf(" ");
|
||||
}
|
||||
n += printf("use=%s,", argv[optind]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (Barg == NULL)
|
||||
unsetenv("TERMINFO");
|
||||
else
|
||||
setdb(Barg);
|
||||
t2 = load_term(argv[optind++]);
|
||||
printf("comparing %s to %s.\n", t->name, t2->name);
|
||||
if (qflag == 0)
|
||||
printf(" comparing booleans.\n");
|
||||
if (nflag == 0) {
|
||||
n = load_ents(ents, t, 'f');
|
||||
n2 = load_ents(ents2, t2, 'f');
|
||||
compare_ents(ents, n, ents2, n2);
|
||||
} else
|
||||
show_missing(t, t2, 'f');
|
||||
if (qflag == 0)
|
||||
printf(" comparing numbers.\n");
|
||||
if (nflag == 0) {
|
||||
n = load_ents(ents, t, 'n');
|
||||
n2 = load_ents(ents2, t2, 'n');
|
||||
compare_ents(ents, n, ents2, n2);
|
||||
} else
|
||||
show_missing(t, t2, 'n');
|
||||
if (qflag == 0)
|
||||
printf(" comparing strings.\n");
|
||||
if (nflag == 0) {
|
||||
n = load_ents(ents, t, 's');
|
||||
n2 = load_ents(ents2, t2, 's');
|
||||
compare_ents(ents, n, ents2, n2);
|
||||
} else
|
||||
show_missing(t, t2, 's');
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in a new issue