--- /dev/null
+.\" $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
--- /dev/null
+/* $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;
+}